SlideShare uma empresa Scribd logo
1 de 53
Baixar para ler offline
Разработка через
  тестирование
в Python и Django
             Илья Шаляпин
         Евгений Генералов
19 проектов
    4 года
89299 строк кода
50826 строк тестов
Писать тесты или нет?
Пример из жизни
Переезд с Ubuntu 8.04 на Ubuntu 12.04

Python 2.5                 Python 2.7
Django 1.3                 Django 1.4.0
lxml 1.3.6                 lxml 2.3.2
PIL 1.1.6                  PIL 1.1.7
...                        ...
Перезд проекта плотно
  покрытого тестами
Перезд проекта менее плотно
    покрытого тестами
Перезд проекта без тестов
Преимущества


- Меньше ручной работы
- Спокойный рефакторинг
- Код легче читать
- Быстрое подключение людей к проекту
- Тесты являются спецификацией
Недостатки


- Затраты на обучение
- Дополнительные настроки в проекте
- Некоторые тесты сложно писать
TDD вид сбоку
$ pip install unittest2
# test_add.py

import unittest2


class AddTest(unittest2.TestCase):

  def test_add(self):
    self.assertEquals(add(1, 1), 2)
    self.assertEquals(add(5, 2), 7)
    self.assertEquals(add(-1, -6), -7)


if __name__ == '__main__':
    unittest2.main()
# test_add.py

import unittest2

def add(a, b):
   pass


class AddTest(unittest2.TestCase):

  def test_add(self):
    self.assertEquals(add(1, 1), 2)


if __name__ == '__main__':
    unittest2.main()
Запуск теста




$ python test_add.py
$ python test_add.py
F
=========================================
FAIL: test_add (__main__.AddTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_add.py", line 11, in test_add
   self.assertEquals(add(1, 1), 2)
AssertionError: None != 2

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)
# test_add.py

import unittest2

def add(a, b):
  return a + b


class AddTest(unittest2.TestCase):

  def test_add(self):
    self.assertEquals(add(1, 1), 2)


if __name__ == '__main__':
    unittest2.main()
$ python test_add.py
.
-------------------------------------------------
Ran 1 test in 0.000s

OK
Проект растет - тестов
  становится много

 ...
 ./tests/
 ./tests/test_add.py
 ./tests/test_sub.py
 ./tests/test_div.py
 ./tests/test_mul.py
 ./tests/test_pi.py
Nose - запускалка тестов
            Устанавливаем nose
$ pip install nose


               Запускаем тесты
$ nosetests
..
--------------------------------------------
Ran 100500 tests in 0.219s

OK
Инструменты




unittest2       django.test
flexmock        django_nose
nose            django_webtest
Тестирование в Django

Установить приложения
   $ pip install django_nose
   $ pip install django_webtest


Создать тестовую конфигурацию
    testing_settings.py
# testing_settings.py
from settings import *

DATABASES = {
  "default": dict(
    ENGINE = "django.db.backends.sqlite3",
    NAME = ":memory:",
  )
}

INSTALLED_APPS += (
  'django_nose',
)

TEST_RUNNER = 'django_nose.
NoseTestSuiteRunner'
Запуск тестов в Django

Запуск всех тестов в папке ./blog

$ manage.py test ./blog --settings project.
testing_settings



Запуск тестов в одном файле

$ manage.py test ./blog/test/test_forms.py --settings
project.testing_settings
Запуск тестов только для одного класса

$ manage.py test ./blog/test/test_forms.py:PostFormTest
--settings project.testing_settings



Запуск только одного теста

$ manage.py test ./blog/test/test_forms.py:PostFormTest.
test_post_from_submit --settings project.testing_settings
Blog tutorial
Тест view

from django.test import TestCase, Client


class HomePageTest(TestCase):

  def test_homepage_is_available(self):
    c = Client()
    response = c.get('/')
    self.assertEquals(response.status_code, 200)
class HomePageTest(TestCase):

  def setUp(self):
    self.posts = [ ]
    for i in range(20):
           post = Post.objects.create(
                 title = "Hello %d" % i,
           )
           self.posts.append(post)

  def test_homepage_contains_posts(self):
    pass
class HomePageTest(TestCase):

  def setUp(self):
    self.posts = [ ]
    for i in range(20):
           post = Post.objects.create(
                 title = "Hello %d" % i,
           )
           self.posts.append(post)

  def test_homepage_contains_posts(self):
    c = Client()
    response = c.get('/')
    self.assertEquals(response.status_code, 200)
    self.assertIn(self.posts[-1].title, response.content)
    self.assertIn(self.posts[-2].title, response.content)
class HomePageTest(TestCase):

  def setUp(self):
    pass

  def tearDown(self):
    pass

  def test_homepage_contains_posts(self):
    pass
def home(request):
  posts = Post.objects.all()[:10]
  return render(request, 'home.html', {'posts':posts})
from django.db import models


class Post(models.Model):
   picture = models.ImageField(
       upload_to='posts', blank=True, null=True)
   title = models.CharField(max_length=255)
   body = models.CharField(max_length=255)

  class Meta:
     ordering = ['-id']
Отправка формы

class PostFormTest(TestCase):

  def test_post_from_submit(self):
    c = Client()
    params = {'title':'Hello Pycon'}
    response = c.post('/posts/add/', params)
    self.assertEquals(response.status_code, 302)
    post = Post.objects.get(title=params['title'])
Загрузка файлов

def test_post_from_submit_with_picture(self):
  f = open('blog/tests/fixtures/debian-logo.png')
  params = {
      'picture':f,
      'title':'My photo',
  }
  response = self.client.post('/posts/add/', params)
  self.assertEquals(response.status_code, 302)
  post = Post.objects.get(title=params['title'])
  self.assertIn('.png', post.picture.path)
$ pip install django_webtest
django_webtest - XPath
class HomePageWebTest(WebTest):

  def setUp(self):
    ...

  def test_homepage_contains_posts(self):
    response = self.app.get('/')
    self.assertEquals(response.status_int, 200)
    titles = response.lxml.xpath(
         "//*[@class='post-announce']/h2/text()"
    )
    self.assertEquals(titles[0], self.posts[-1].title)
    self.assertEquals(titles[1], self.posts[-2].title)
django_webtest - формы

from django_webtest import WebTest

class PostFormWebTest(WebTest):

  def test_post_from_submit(self):
    response = self.app.get('/posts/add/')
    self.assertEquals(response.status_int, 200)
    form = response.forms['add_post_form']
    form['title'] = 'Hello Pycon'
    form['body'] = 'Wazzup!'
    response = form.submit().follow()
    self.assertEquals(response.status_int, 200)
Тесты админки




Почти такие же как тесты других view
class PostAdminTest(TestCase):

  def setUp(self):
    self.user = User.objects.create_user(
       'admin',
       'mail@example.com',
       'password'
    )
    self.user.is_staff = True
    self.user.is_superuser = True
    self.user.save()

  def test_post_form_submit(self):
    ...
class PostAdminTest(TestCase):

  def setUp(self):
    ...

  def test_post_form_submit(self):
    c = Client()
    c.login(username='admin', password='password')
    response = c.get('/admin/blog/post/add/')
    self.assertEquals(response.status_code, 200)
    params = {'title': 'Hello Pycon', 'body': 'Text'}
    response = c.post('/posts/add/', params)
    self.assertEquals(response.status_code, 302)
    post = Post.objects.get(title=params['title'])
Прочее в Django

- Middleware
- Template tags, filters
- Context processors


- тестируются модульными тестами как
простые функции, аналогично с
примером 1+1 = 2
Особенности тестов view в Django

     ----------------------------
     middleware
     -----------------------------
     context processors
     -----------------------------
     template
     -----------------------------
     view
     -----------------------------
     models
     -----------------------------
     network
Flexmock

- Заменять части объектов и классов
- Заменять функции, в том числе
встроенные
- Создавать объекты заглушки
- Проверять ожидания (сколько раз
вызван метод, с какими аргументами)
$ pip install flexmock
from flexmock import flexmock
from blog.models import Post

def test_home_page_with_flexmock(self):
  posts = [
     Post(title='hello flexmock'),
     Post(title='hello flexmock'),
  ]
  (flexmock(Post.objects)
     .should_receive('all')
     .and_return(posts)
     .once())
  response = self.client.get('/')
  self.assertEquals(response.status_code, 200)
  self.assertIn('hello flexmock', response.content)
from flexmock import flexmock
import blog.views

def test_home_view_as_unittest(self):
  request = flexmock(
     GET={},
     POST={},
     META={'HTTP_HOST':'example.com'}
  )
  response = blog.views.home(request)
  self.assertEquals(response.status_code, 200)
Теория vs практика
Есть требования ...

def get_url_content(url):
  # ToDo
  # Вернуть контент страницы
  # или None, в случае ошибки
  pass
Как написать тест?



def test_get_url_content(self):
  url = 'http://example.com'
  text = get_url_content(url)
  self.assertEquals(text, ???)
Тестирование реализации
Пишем тест имея представление о внутренностях

def get_url_content(url):
  try:
     response = urllib.urlopen(url)
     content = response.read()
     response.close()
  except IOError:
     return None
  return content


Неверно с точки зрения теории,
удобно на практике
Тест для случая нормального
        выполнения
 def test_get_url_content(self):
   url = 'http://example.com'
   response = StringIO("<html>")
   (flexmock(urllib)
      .should_receive('urlopen')
      .with_args(url)
      .and_return(response)
      .once())
   text = get_url_content(url)
   self.assertEquals(text, "<html>")
Тест в случае ошибки сети

def test_get_url_content_on_ioerror(self):
  url = 'http://example.com'
  (flexmock(urllib)
     .should_receive('urlopen')
     .with_args(url)
     .and_raise(IOError("test exception"))
     .once())
  text = get_url_content(url)
  self.assertEquals(text, None)
Примеры тестов



https://bitbucket.org/ishalyapin/python-test-examples

https://bitbucket.org/ishalyapin/django-test-examples
Спасибо за внимание!
  Доклад подготовили

 Илья Шаляпин
 ishalyapin@gmail.com
 www.ishalyapin.ru
 www.bookradar.org
 bitbucket.org/ishalyapin
 github.com/un1t



 Евгений Генералов
 e.generalov@gmail.com
 github.com/generalov

Mais conteúdo relacionado

Mais procurados

ZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to UsZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to UsZFConf Conference
 
Web осень 2013 лекция 7
Web осень 2013 лекция 7Web осень 2013 лекция 7
Web осень 2013 лекция 7Technopark
 
Unit testing iOS Applications
Unit testing iOS ApplicationsUnit testing iOS Applications
Unit testing iOS ApplicationsAndrey Volobuev
 
Web осень 2013 лекция 8
Web осень 2013 лекция 8Web осень 2013 лекция 8
Web осень 2013 лекция 8Technopark
 
Нескучное тестирование с pytest
Нескучное тестирование с pytestНескучное тестирование с pytest
Нескучное тестирование с pytestRoman Imankulov
 
C# Desktop. Занятие 12.
C# Desktop. Занятие 12.C# Desktop. Занятие 12.
C# Desktop. Занятие 12.Igor Shkulipa
 
Web осень 2013 лекция 4
Web осень 2013 лекция 4Web осень 2013 лекция 4
Web осень 2013 лекция 4Technopark
 
Лекция 6. Классы 1.
Лекция 6. Классы 1.Лекция 6. Классы 1.
Лекция 6. Классы 1.Roman Brovko
 
Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"Python Meetup
 
Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3Яковенко Кирилл
 
Лекция 5. Встроенные коллекции и модуль collections.
Лекция 5. Встроенные коллекции и модуль collections.Лекция 5. Встроенные коллекции и модуль collections.
Лекция 5. Встроенные коллекции и модуль collections.Roman Brovko
 
Javascript testing
Javascript testingJavascript testing
Javascript testingTCS bank
 
Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0matroskin1980
 
Angular 2: Всех переиграл
Angular 2: Всех переигралAngular 2: Всех переиграл
Angular 2: Всех переигралEugene Zharkov
 

Mais procurados (19)

бегун
бегунбегун
бегун
 
ZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to UsZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to Us
 
Web осень 2013 лекция 7
Web осень 2013 лекция 7Web осень 2013 лекция 7
Web осень 2013 лекция 7
 
Unit testing iOS Applications
Unit testing iOS ApplicationsUnit testing iOS Applications
Unit testing iOS Applications
 
Zend Framework и Doctrine
Zend Framework и DoctrineZend Framework и Doctrine
Zend Framework и Doctrine
 
Web осень 2013 лекция 8
Web осень 2013 лекция 8Web осень 2013 лекция 8
Web осень 2013 лекция 8
 
Нескучное тестирование с pytest
Нескучное тестирование с pytestНескучное тестирование с pytest
Нескучное тестирование с pytest
 
C# Desktop. Занятие 12.
C# Desktop. Занятие 12.C# Desktop. Занятие 12.
C# Desktop. Занятие 12.
 
Dependency injection, phemto
Dependency injection, phemtoDependency injection, phemto
Dependency injection, phemto
 
Web осень 2013 лекция 4
Web осень 2013 лекция 4Web осень 2013 лекция 4
Web осень 2013 лекция 4
 
Лекция 6. Классы 1.
Лекция 6. Классы 1.Лекция 6. Классы 1.
Лекция 6. Классы 1.
 
Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"
 
Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3
 
Лекция 5. Встроенные коллекции и модуль collections.
Лекция 5. Встроенные коллекции и модуль collections.Лекция 5. Встроенные коллекции и модуль collections.
Лекция 5. Встроенные коллекции и модуль collections.
 
Selenium vs AJAX
Selenium vs AJAXSelenium vs AJAX
Selenium vs AJAX
 
Javascript testing
Javascript testingJavascript testing
Javascript testing
 
Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0
 
Angular 2: Всех переиграл
Angular 2: Всех переигралAngular 2: Всех переиграл
Angular 2: Всех переиграл
 
Drf vs Graphql
Drf vs GraphqlDrf vs Graphql
Drf vs Graphql
 

Destaque

Алексей Кулаков: Доклад о ненависти к рыбе...и любви к осмысленному тексту
Алексей Кулаков: Доклад о ненависти к рыбе...и любви к осмысленному текстуАлексей Кулаков: Доклад о ненависти к рыбе...и любви к осмысленному тексту
Алексей Кулаков: Доклад о ненависти к рыбе...и любви к осмысленному текстуJetStyle
 
Разработка сайта как создание мультфильма #oseminar
Разработка сайта как создание мультфильма #oseminarРазработка сайта как создание мультфильма #oseminar
Разработка сайта как создание мультфильма #oseminarJetStyle
 
Илья Седов: Как заставить программу под iOS шевелиться? #uwdc
Илья Седов: Как заставить программу под iOS шевелиться? #uwdcИлья Седов: Как заставить программу под iOS шевелиться? #uwdc
Илья Седов: Как заставить программу под iOS шевелиться? #uwdcJetStyle
 
Алексей Кулаков: Теория ограничений Голдратта #oseminar
Алексей Кулаков: Теория ограничений Голдратта #oseminarАлексей Кулаков: Теория ограничений Голдратта #oseminar
Алексей Кулаков: Теория ограничений Голдратта #oseminarJetStyle
 
Минисервисы или микросервисы в условия цейтнота, Руслан Каримов, UWDC 2015
Минисервисы или микросервисы в условия цейтнота, Руслан Каримов, UWDC 2015Минисервисы или микросервисы в условия цейтнота, Руслан Каримов, UWDC 2015
Минисервисы или микросервисы в условия цейтнота, Руслан Каримов, UWDC 2015JetStyle
 
Как выжить в условиях сложного продукта. Дарья Прокуда.
Как выжить в условиях сложного продукта. Дарья Прокуда.Как выжить в условиях сложного продукта. Дарья Прокуда.
Как выжить в условиях сложного продукта. Дарья Прокуда.JetStyle
 
Битва мух и котлет. Сторителлинг в проектировании взаимодействия.
Битва мух и котлет. Сторителлинг в проектировании взаимодействия. Битва мух и котлет. Сторителлинг в проектировании взаимодействия.
Битва мух и котлет. Сторителлинг в проектировании взаимодействия. JetStyle
 
Об особенностях работы художника, который гипотетически может все
Об особенностях работы художника, который гипотетически может всеОб особенностях работы художника, который гипотетически может все
Об особенностях работы художника, который гипотетически может всеJetStyle
 
Исследовательские проекты в жизненном цикле и рутинных процессах компании
Исследовательские проекты в жизненном цикле и рутинных процессах компанииИсследовательские проекты в жизненном цикле и рутинных процессах компании
Исследовательские проекты в жизненном цикле и рутинных процессах компанииJetStyle
 
Автоматизация общения с менеджером, Полина Бынова, JetStyle
Автоматизация общения с менеджером, Полина Бынова, JetStyleАвтоматизация общения с менеджером, Полина Бынова, JetStyle
Автоматизация общения с менеджером, Полина Бынова, JetStyleJetStyle
 
Данные на службе бизнеса
Данные на службе бизнесаДанные на службе бизнеса
Данные на службе бизнесаJetStyle
 
CPC-трафик в unit-экономике, Полина Бынова
CPC-трафик в unit-экономике, Полина БыноваCPC-трафик в unit-экономике, Полина Бынова
CPC-трафик в unit-экономике, Полина БыноваJetStyle
 
Сергей Беляев: Интернет-телевизор - самый недооцененный сегмент разработки #uwdc
Сергей Беляев: Интернет-телевизор - самый недооцененный сегмент разработки #uwdcСергей Беляев: Интернет-телевизор - самый недооцененный сегмент разработки #uwdc
Сергей Беляев: Интернет-телевизор - самый недооцененный сегмент разработки #uwdcJetStyle
 
Управление - это игра. Алексей Кулаков, JetStyle
Управление - это игра. Алексей Кулаков, JetStyleУправление - это игра. Алексей Кулаков, JetStyle
Управление - это игра. Алексей Кулаков, JetStyleJetStyle
 
MVP (минимальный жизнеспособный продукт): как не потерять деньги на разработк...
MVP (минимальный жизнеспособный продукт): как не потерять деньги на разработк...MVP (минимальный жизнеспособный продукт): как не потерять деньги на разработк...
MVP (минимальный жизнеспособный продукт): как не потерять деньги на разработк...dkalaev
 
Создание нового стиля, дизайна и шрифта для "Батенька, да вы трансформер!"
Создание нового стиля, дизайна и шрифта для "Батенька, да вы трансформер!"Создание нового стиля, дизайна и шрифта для "Батенька, да вы трансформер!"
Создание нового стиля, дизайна и шрифта для "Батенька, да вы трансформер!"JetStyle
 
Разработка MVP. Зачем это нужно и как это делать?
Разработка MVP. Зачем это нужно и как это делать? Разработка MVP. Зачем это нужно и как это делать?
Разработка MVP. Зачем это нужно и как это делать? JetStyle
 

Destaque (17)

Алексей Кулаков: Доклад о ненависти к рыбе...и любви к осмысленному тексту
Алексей Кулаков: Доклад о ненависти к рыбе...и любви к осмысленному текстуАлексей Кулаков: Доклад о ненависти к рыбе...и любви к осмысленному тексту
Алексей Кулаков: Доклад о ненависти к рыбе...и любви к осмысленному тексту
 
Разработка сайта как создание мультфильма #oseminar
Разработка сайта как создание мультфильма #oseminarРазработка сайта как создание мультфильма #oseminar
Разработка сайта как создание мультфильма #oseminar
 
Илья Седов: Как заставить программу под iOS шевелиться? #uwdc
Илья Седов: Как заставить программу под iOS шевелиться? #uwdcИлья Седов: Как заставить программу под iOS шевелиться? #uwdc
Илья Седов: Как заставить программу под iOS шевелиться? #uwdc
 
Алексей Кулаков: Теория ограничений Голдратта #oseminar
Алексей Кулаков: Теория ограничений Голдратта #oseminarАлексей Кулаков: Теория ограничений Голдратта #oseminar
Алексей Кулаков: Теория ограничений Голдратта #oseminar
 
Минисервисы или микросервисы в условия цейтнота, Руслан Каримов, UWDC 2015
Минисервисы или микросервисы в условия цейтнота, Руслан Каримов, UWDC 2015Минисервисы или микросервисы в условия цейтнота, Руслан Каримов, UWDC 2015
Минисервисы или микросервисы в условия цейтнота, Руслан Каримов, UWDC 2015
 
Как выжить в условиях сложного продукта. Дарья Прокуда.
Как выжить в условиях сложного продукта. Дарья Прокуда.Как выжить в условиях сложного продукта. Дарья Прокуда.
Как выжить в условиях сложного продукта. Дарья Прокуда.
 
Битва мух и котлет. Сторителлинг в проектировании взаимодействия.
Битва мух и котлет. Сторителлинг в проектировании взаимодействия. Битва мух и котлет. Сторителлинг в проектировании взаимодействия.
Битва мух и котлет. Сторителлинг в проектировании взаимодействия.
 
Об особенностях работы художника, который гипотетически может все
Об особенностях работы художника, который гипотетически может всеОб особенностях работы художника, который гипотетически может все
Об особенностях работы художника, который гипотетически может все
 
Исследовательские проекты в жизненном цикле и рутинных процессах компании
Исследовательские проекты в жизненном цикле и рутинных процессах компанииИсследовательские проекты в жизненном цикле и рутинных процессах компании
Исследовательские проекты в жизненном цикле и рутинных процессах компании
 
Автоматизация общения с менеджером, Полина Бынова, JetStyle
Автоматизация общения с менеджером, Полина Бынова, JetStyleАвтоматизация общения с менеджером, Полина Бынова, JetStyle
Автоматизация общения с менеджером, Полина Бынова, JetStyle
 
Данные на службе бизнеса
Данные на службе бизнесаДанные на службе бизнеса
Данные на службе бизнеса
 
CPC-трафик в unit-экономике, Полина Бынова
CPC-трафик в unit-экономике, Полина БыноваCPC-трафик в unit-экономике, Полина Бынова
CPC-трафик в unit-экономике, Полина Бынова
 
Сергей Беляев: Интернет-телевизор - самый недооцененный сегмент разработки #uwdc
Сергей Беляев: Интернет-телевизор - самый недооцененный сегмент разработки #uwdcСергей Беляев: Интернет-телевизор - самый недооцененный сегмент разработки #uwdc
Сергей Беляев: Интернет-телевизор - самый недооцененный сегмент разработки #uwdc
 
Управление - это игра. Алексей Кулаков, JetStyle
Управление - это игра. Алексей Кулаков, JetStyleУправление - это игра. Алексей Кулаков, JetStyle
Управление - это игра. Алексей Кулаков, JetStyle
 
MVP (минимальный жизнеспособный продукт): как не потерять деньги на разработк...
MVP (минимальный жизнеспособный продукт): как не потерять деньги на разработк...MVP (минимальный жизнеспособный продукт): как не потерять деньги на разработк...
MVP (минимальный жизнеспособный продукт): как не потерять деньги на разработк...
 
Создание нового стиля, дизайна и шрифта для "Батенька, да вы трансформер!"
Создание нового стиля, дизайна и шрифта для "Батенька, да вы трансформер!"Создание нового стиля, дизайна и шрифта для "Батенька, да вы трансформер!"
Создание нового стиля, дизайна и шрифта для "Батенька, да вы трансформер!"
 
Разработка MVP. Зачем это нужно и как это делать?
Разработка MVP. Зачем это нужно и как это делать? Разработка MVP. Зачем это нужно и как это делать?
Разработка MVP. Зачем это нужно и как это делать?
 

Semelhante a Разработка через тестирование в Python и Django #pyconru

Web весна 2012 лекция 7
Web весна 2012 лекция 7Web весна 2012 лекция 7
Web весна 2012 лекция 7Technopark
 
"VUE.JS как реакт с человеческим лицом" Дулецкий Вольдэмар, Evrone
"VUE.JS как реакт с человеческим лицом" Дулецкий Вольдэмар, Evrone"VUE.JS как реакт с человеческим лицом" Дулецкий Вольдэмар, Evrone
"VUE.JS как реакт с человеческим лицом" Дулецкий Вольдэмар, Evroneit-people
 
12 - Web-технологии. Django модели
12 - Web-технологии. Django модели12 - Web-технологии. Django модели
12 - Web-технологии. Django моделиRoman Brovko
 
Magento code debugging
Magento code debuggingMagento code debugging
Magento code debuggingaheadWorks
 
Meet Magento Belarus debug Pavel Novitsky (rus)
Meet Magento Belarus debug Pavel Novitsky (rus)Meet Magento Belarus debug Pavel Novitsky (rus)
Meet Magento Belarus debug Pavel Novitsky (rus)Pavel Novitsky
 
Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...
Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...
Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...Andrey Rebrov
 
TestGuy - эмулируем вашего тестировщика
TestGuy - эмулируем вашего тестировщикаTestGuy - эмулируем вашего тестировщика
TestGuy - эмулируем вашего тестировщикаdavertmik
 
Django South. Миграция баз данных.
Django South. Миграция баз данных.  Django South. Миграция баз данных.
Django South. Миграция баз данных. MoscowDjango
 
Looking into WordPress Core, WordCamp Russia 2015
Looking into WordPress Core, WordCamp Russia 2015Looking into WordPress Core, WordCamp Russia 2015
Looking into WordPress Core, WordCamp Russia 2015Sergey Biryukov
 
вебинар - функциональное тестирование с использованием Selenium 2 и TestNG
вебинар - функциональное тестирование с использованием Selenium 2 и TestNGвебинар - функциональное тестирование с использованием Selenium 2 и TestNG
вебинар - функциональное тестирование с использованием Selenium 2 и TestNGAndrey Rebrov
 
Первые шаги после установки WordPress
Первые шаги после установки WordPressПервые шаги после установки WordPress
Первые шаги после установки WordPressDarja Kruzhkova
 
Mobile automation uamobile
Mobile automation uamobileMobile automation uamobile
Mobile automation uamobileUA Mobile
 
Производительность в Django
Производительность в DjangoПроизводительность в Django
Производительность в DjangoMoscowDjango
 
TestRail. Некоторые возможности интеграции.
TestRail. Некоторые возможности интеграции.TestRail. Некоторые возможности интеграции.
TestRail. Некоторые возможности интеграции.PyNSK
 
iOS and Android Mobile Test Automation
iOS and Android Mobile Test AutomationiOS and Android Mobile Test Automation
iOS and Android Mobile Test AutomationAndrii Dzynia
 
Дело тестера боится: как в опытных руках могут заиграть Java и TestNg
Дело тестера боится: как в опытных руках могут заиграть Java и TestNgДело тестера боится: как в опытных руках могут заиграть Java и TestNg
Дело тестера боится: как в опытных руках могут заиграть Java и TestNgIT61
 
Python Meetup
Python Meetup Python Meetup
Python Meetup iQSpace
 
10 - Web-технологии. MVC фреймворки (продолжение)
10 - Web-технологии. MVC фреймворки (продолжение)10 - Web-технологии. MVC фреймворки (продолжение)
10 - Web-технологии. MVC фреймворки (продолжение)Roman Brovko
 

Semelhante a Разработка через тестирование в Python и Django #pyconru (20)

Web весна 2012 лекция 7
Web весна 2012 лекция 7Web весна 2012 лекция 7
Web весна 2012 лекция 7
 
"VUE.JS как реакт с человеческим лицом" Дулецкий Вольдэмар, Evrone
"VUE.JS как реакт с человеческим лицом" Дулецкий Вольдэмар, Evrone"VUE.JS как реакт с человеческим лицом" Дулецкий Вольдэмар, Evrone
"VUE.JS как реакт с человеческим лицом" Дулецкий Вольдэмар, Evrone
 
12 - Web-технологии. Django модели
12 - Web-технологии. Django модели12 - Web-технологии. Django модели
12 - Web-технологии. Django модели
 
Magento code debugging
Magento code debuggingMagento code debugging
Magento code debugging
 
Meet Magento Belarus debug Pavel Novitsky (rus)
Meet Magento Belarus debug Pavel Novitsky (rus)Meet Magento Belarus debug Pavel Novitsky (rus)
Meet Magento Belarus debug Pavel Novitsky (rus)
 
Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...
Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...
Бодрящий микс из Selenium и TestNG- регрессионное тестирование руками разрабо...
 
TestGuy - эмулируем вашего тестировщика
TestGuy - эмулируем вашего тестировщикаTestGuy - эмулируем вашего тестировщика
TestGuy - эмулируем вашего тестировщика
 
Django South. Миграция баз данных.
Django South. Миграция баз данных.  Django South. Миграция баз данных.
Django South. Миграция баз данных.
 
бегун
бегунбегун
бегун
 
Looking into WordPress Core, WordCamp Russia 2015
Looking into WordPress Core, WordCamp Russia 2015Looking into WordPress Core, WordCamp Russia 2015
Looking into WordPress Core, WordCamp Russia 2015
 
вебинар - функциональное тестирование с использованием Selenium 2 и TestNG
вебинар - функциональное тестирование с использованием Selenium 2 и TestNGвебинар - функциональное тестирование с использованием Selenium 2 и TestNG
вебинар - функциональное тестирование с использованием Selenium 2 и TestNG
 
Первые шаги после установки WordPress
Первые шаги после установки WordPressПервые шаги после установки WordPress
Первые шаги после установки WordPress
 
Mobile automation uamobile
Mobile automation uamobileMobile automation uamobile
Mobile automation uamobile
 
Производительность в Django
Производительность в DjangoПроизводительность в Django
Производительность в Django
 
TestRail. Некоторые возможности интеграции.
TestRail. Некоторые возможности интеграции.TestRail. Некоторые возможности интеграции.
TestRail. Некоторые возможности интеграции.
 
iOS and Android Mobile Test Automation
iOS and Android Mobile Test AutomationiOS and Android Mobile Test Automation
iOS and Android Mobile Test Automation
 
Дело тестера боится: как в опытных руках могут заиграть Java и TestNg
Дело тестера боится: как в опытных руках могут заиграть Java и TestNgДело тестера боится: как в опытных руках могут заиграть Java и TestNg
Дело тестера боится: как в опытных руках могут заиграть Java и TestNg
 
Python Meetup
Python Meetup Python Meetup
Python Meetup
 
10 - Web-технологии. MVC фреймворки (продолжение)
10 - Web-технологии. MVC фреймворки (продолжение)10 - Web-технологии. MVC фреймворки (продолжение)
10 - Web-технологии. MVC фреймворки (продолжение)
 
Erlang tasty & useful stuff
Erlang tasty & useful stuffErlang tasty & useful stuff
Erlang tasty & useful stuff
 

Mais de JetStyle

Нарративные игры как метод прототипирования, Алексей Кулаков, UWDC 2015
Нарративные игры как метод прототипирования, Алексей Кулаков, UWDC 2015Нарративные игры как метод прототипирования, Алексей Кулаков, UWDC 2015
Нарративные игры как метод прототипирования, Алексей Кулаков, UWDC 2015JetStyle
 
Постановка задачи на сайт. Алексей Кулаков
Постановка задачи на сайт. Алексей КулаковПостановка задачи на сайт. Алексей Кулаков
Постановка задачи на сайт. Алексей КулаковJetStyle
 
Как узнать о ваших покупателях все?
Как узнать о ваших покупателях все?Как узнать о ваших покупателях все?
Как узнать о ваших покупателях все?JetStyle
 
Петли в проектировании интерфейсов, DUMP 2014
Петли в проектировании интерфейсов, DUMP 2014Петли в проектировании интерфейсов, DUMP 2014
Петли в проектировании интерфейсов, DUMP 2014JetStyle
 
Как создать зарабатывающее приложение, UIN 2014
Как создать зарабатывающее приложение, UIN 2014Как создать зарабатывающее приложение, UIN 2014
Как создать зарабатывающее приложение, UIN 2014JetStyle
 
Frontttalks nov2013
Frontttalks nov2013Frontttalks nov2013
Frontttalks nov2013JetStyle
 
DUMP-2013 - Frontend: Преимущества разработки средствами BEM+Python+node.js
DUMP-2013 - Frontend: Преимущества разработки средствами BEM+Python+node.jsDUMP-2013 - Frontend: Преимущества разработки средствами BEM+Python+node.js
DUMP-2013 - Frontend: Преимущества разработки средствами BEM+Python+node.jsJetStyle
 
Мобильное приложение для бизнеса: взгляд со стороны разработчика
Мобильное приложение для бизнеса: взгляд со стороны разработчикаМобильное приложение для бизнеса: взгляд со стороны разработчика
Мобильное приложение для бизнеса: взгляд со стороны разработчикаJetStyle
 
Интерфейсы для Smart TV #uxsreda
Интерфейсы для Smart TV #uxsredaИнтерфейсы для Smart TV #uxsreda
Интерфейсы для Smart TV #uxsredaJetStyle
 
Алексей Кулаков: Суеверия vs научный подход в проектировании интерфейсов #uwdc
Алексей Кулаков: Суеверия vs научный подход в проектировании интерфейсов #uwdcАлексей Кулаков: Суеверия vs научный подход в проектировании интерфейсов #uwdc
Алексей Кулаков: Суеверия vs научный подход в проектировании интерфейсов #uwdcJetStyle
 
Борис Касавин: Big data для нужд реального российского бизнеса #uwdc
Борис Касавин: Big data для нужд реального российского бизнеса #uwdcБорис Касавин: Big data для нужд реального российского бизнеса #uwdc
Борис Касавин: Big data для нужд реального российского бизнеса #uwdcJetStyle
 
Алексей Иванов: немного о grunt.js #FrontTalks
Алексей Иванов: немного о grunt.js #FrontTalksАлексей Иванов: немного о grunt.js #FrontTalks
Алексей Иванов: немного о grunt.js #FrontTalksJetStyle
 
Александр Устинов: Работа с существующими клиентами (бизнес-завтрак)
Александр Устинов: Работа с существующими клиентами (бизнес-завтрак)Александр Устинов: Работа с существующими клиентами (бизнес-завтрак)
Александр Устинов: Работа с существующими клиентами (бизнес-завтрак)JetStyle
 
Сергей Наймушин: Управление привлечением новых клиентов (бизнес-завтрак)
Сергей Наймушин: Управление привлечением новых клиентов (бизнес-завтрак)Сергей Наймушин: Управление привлечением новых клиентов (бизнес-завтрак)
Сергей Наймушин: Управление привлечением новых клиентов (бизнес-завтрак)JetStyle
 

Mais de JetStyle (14)

Нарративные игры как метод прототипирования, Алексей Кулаков, UWDC 2015
Нарративные игры как метод прототипирования, Алексей Кулаков, UWDC 2015Нарративные игры как метод прототипирования, Алексей Кулаков, UWDC 2015
Нарративные игры как метод прототипирования, Алексей Кулаков, UWDC 2015
 
Постановка задачи на сайт. Алексей Кулаков
Постановка задачи на сайт. Алексей КулаковПостановка задачи на сайт. Алексей Кулаков
Постановка задачи на сайт. Алексей Кулаков
 
Как узнать о ваших покупателях все?
Как узнать о ваших покупателях все?Как узнать о ваших покупателях все?
Как узнать о ваших покупателях все?
 
Петли в проектировании интерфейсов, DUMP 2014
Петли в проектировании интерфейсов, DUMP 2014Петли в проектировании интерфейсов, DUMP 2014
Петли в проектировании интерфейсов, DUMP 2014
 
Как создать зарабатывающее приложение, UIN 2014
Как создать зарабатывающее приложение, UIN 2014Как создать зарабатывающее приложение, UIN 2014
Как создать зарабатывающее приложение, UIN 2014
 
Frontttalks nov2013
Frontttalks nov2013Frontttalks nov2013
Frontttalks nov2013
 
DUMP-2013 - Frontend: Преимущества разработки средствами BEM+Python+node.js
DUMP-2013 - Frontend: Преимущества разработки средствами BEM+Python+node.jsDUMP-2013 - Frontend: Преимущества разработки средствами BEM+Python+node.js
DUMP-2013 - Frontend: Преимущества разработки средствами BEM+Python+node.js
 
Мобильное приложение для бизнеса: взгляд со стороны разработчика
Мобильное приложение для бизнеса: взгляд со стороны разработчикаМобильное приложение для бизнеса: взгляд со стороны разработчика
Мобильное приложение для бизнеса: взгляд со стороны разработчика
 
Интерфейсы для Smart TV #uxsreda
Интерфейсы для Smart TV #uxsredaИнтерфейсы для Smart TV #uxsreda
Интерфейсы для Smart TV #uxsreda
 
Алексей Кулаков: Суеверия vs научный подход в проектировании интерфейсов #uwdc
Алексей Кулаков: Суеверия vs научный подход в проектировании интерфейсов #uwdcАлексей Кулаков: Суеверия vs научный подход в проектировании интерфейсов #uwdc
Алексей Кулаков: Суеверия vs научный подход в проектировании интерфейсов #uwdc
 
Борис Касавин: Big data для нужд реального российского бизнеса #uwdc
Борис Касавин: Big data для нужд реального российского бизнеса #uwdcБорис Касавин: Big data для нужд реального российского бизнеса #uwdc
Борис Касавин: Big data для нужд реального российского бизнеса #uwdc
 
Алексей Иванов: немного о grunt.js #FrontTalks
Алексей Иванов: немного о grunt.js #FrontTalksАлексей Иванов: немного о grunt.js #FrontTalks
Алексей Иванов: немного о grunt.js #FrontTalks
 
Александр Устинов: Работа с существующими клиентами (бизнес-завтрак)
Александр Устинов: Работа с существующими клиентами (бизнес-завтрак)Александр Устинов: Работа с существующими клиентами (бизнес-завтрак)
Александр Устинов: Работа с существующими клиентами (бизнес-завтрак)
 
Сергей Наймушин: Управление привлечением новых клиентов (бизнес-завтрак)
Сергей Наймушин: Управление привлечением новых клиентов (бизнес-завтрак)Сергей Наймушин: Управление привлечением новых клиентов (бизнес-завтрак)
Сергей Наймушин: Управление привлечением новых клиентов (бизнес-завтрак)
 

Разработка через тестирование в Python и Django #pyconru

  • 1. Разработка через тестирование в Python и Django Илья Шаляпин Евгений Генералов
  • 2. 19 проектов 4 года 89299 строк кода 50826 строк тестов
  • 4. Пример из жизни Переезд с Ubuntu 8.04 на Ubuntu 12.04 Python 2.5 Python 2.7 Django 1.3 Django 1.4.0 lxml 1.3.6 lxml 2.3.2 PIL 1.1.6 PIL 1.1.7 ... ...
  • 5. Перезд проекта плотно покрытого тестами
  • 6. Перезд проекта менее плотно покрытого тестами
  • 8. Преимущества - Меньше ручной работы - Спокойный рефакторинг - Код легче читать - Быстрое подключение людей к проекту - Тесты являются спецификацией
  • 9. Недостатки - Затраты на обучение - Дополнительные настроки в проекте - Некоторые тесты сложно писать
  • 11. $ pip install unittest2
  • 12. # test_add.py import unittest2 class AddTest(unittest2.TestCase): def test_add(self): self.assertEquals(add(1, 1), 2) self.assertEquals(add(5, 2), 7) self.assertEquals(add(-1, -6), -7) if __name__ == '__main__': unittest2.main()
  • 13. # test_add.py import unittest2 def add(a, b): pass class AddTest(unittest2.TestCase): def test_add(self): self.assertEquals(add(1, 1), 2) if __name__ == '__main__': unittest2.main()
  • 15. $ python test_add.py F ========================================= FAIL: test_add (__main__.AddTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_add.py", line 11, in test_add self.assertEquals(add(1, 1), 2) AssertionError: None != 2 ---------------------------------------------------------------------- Ran 1 test in 0.000s FAILED (failures=1)
  • 16. # test_add.py import unittest2 def add(a, b): return a + b class AddTest(unittest2.TestCase): def test_add(self): self.assertEquals(add(1, 1), 2) if __name__ == '__main__': unittest2.main()
  • 18. Проект растет - тестов становится много ... ./tests/ ./tests/test_add.py ./tests/test_sub.py ./tests/test_div.py ./tests/test_mul.py ./tests/test_pi.py
  • 19. Nose - запускалка тестов Устанавливаем nose $ pip install nose Запускаем тесты $ nosetests .. -------------------------------------------- Ran 100500 tests in 0.219s OK
  • 20. Инструменты unittest2 django.test flexmock django_nose nose django_webtest
  • 21. Тестирование в Django Установить приложения $ pip install django_nose $ pip install django_webtest Создать тестовую конфигурацию testing_settings.py
  • 22. # testing_settings.py from settings import * DATABASES = { "default": dict( ENGINE = "django.db.backends.sqlite3", NAME = ":memory:", ) } INSTALLED_APPS += ( 'django_nose', ) TEST_RUNNER = 'django_nose. NoseTestSuiteRunner'
  • 23. Запуск тестов в Django Запуск всех тестов в папке ./blog $ manage.py test ./blog --settings project. testing_settings Запуск тестов в одном файле $ manage.py test ./blog/test/test_forms.py --settings project.testing_settings
  • 24. Запуск тестов только для одного класса $ manage.py test ./blog/test/test_forms.py:PostFormTest --settings project.testing_settings Запуск только одного теста $ manage.py test ./blog/test/test_forms.py:PostFormTest. test_post_from_submit --settings project.testing_settings
  • 26. Тест view from django.test import TestCase, Client class HomePageTest(TestCase): def test_homepage_is_available(self): c = Client() response = c.get('/') self.assertEquals(response.status_code, 200)
  • 27. class HomePageTest(TestCase): def setUp(self): self.posts = [ ] for i in range(20): post = Post.objects.create( title = "Hello %d" % i, ) self.posts.append(post) def test_homepage_contains_posts(self): pass
  • 28. class HomePageTest(TestCase): def setUp(self): self.posts = [ ] for i in range(20): post = Post.objects.create( title = "Hello %d" % i, ) self.posts.append(post) def test_homepage_contains_posts(self): c = Client() response = c.get('/') self.assertEquals(response.status_code, 200) self.assertIn(self.posts[-1].title, response.content) self.assertIn(self.posts[-2].title, response.content)
  • 29. class HomePageTest(TestCase): def setUp(self): pass def tearDown(self): pass def test_homepage_contains_posts(self): pass
  • 30. def home(request): posts = Post.objects.all()[:10] return render(request, 'home.html', {'posts':posts})
  • 31. from django.db import models class Post(models.Model): picture = models.ImageField( upload_to='posts', blank=True, null=True) title = models.CharField(max_length=255) body = models.CharField(max_length=255) class Meta: ordering = ['-id']
  • 32. Отправка формы class PostFormTest(TestCase): def test_post_from_submit(self): c = Client() params = {'title':'Hello Pycon'} response = c.post('/posts/add/', params) self.assertEquals(response.status_code, 302) post = Post.objects.get(title=params['title'])
  • 33. Загрузка файлов def test_post_from_submit_with_picture(self): f = open('blog/tests/fixtures/debian-logo.png') params = { 'picture':f, 'title':'My photo', } response = self.client.post('/posts/add/', params) self.assertEquals(response.status_code, 302) post = Post.objects.get(title=params['title']) self.assertIn('.png', post.picture.path)
  • 34. $ pip install django_webtest
  • 35. django_webtest - XPath class HomePageWebTest(WebTest): def setUp(self): ... def test_homepage_contains_posts(self): response = self.app.get('/') self.assertEquals(response.status_int, 200) titles = response.lxml.xpath( "//*[@class='post-announce']/h2/text()" ) self.assertEquals(titles[0], self.posts[-1].title) self.assertEquals(titles[1], self.posts[-2].title)
  • 36. django_webtest - формы from django_webtest import WebTest class PostFormWebTest(WebTest): def test_post_from_submit(self): response = self.app.get('/posts/add/') self.assertEquals(response.status_int, 200) form = response.forms['add_post_form'] form['title'] = 'Hello Pycon' form['body'] = 'Wazzup!' response = form.submit().follow() self.assertEquals(response.status_int, 200)
  • 37. Тесты админки Почти такие же как тесты других view
  • 38. class PostAdminTest(TestCase): def setUp(self): self.user = User.objects.create_user( 'admin', 'mail@example.com', 'password' ) self.user.is_staff = True self.user.is_superuser = True self.user.save() def test_post_form_submit(self): ...
  • 39. class PostAdminTest(TestCase): def setUp(self): ... def test_post_form_submit(self): c = Client() c.login(username='admin', password='password') response = c.get('/admin/blog/post/add/') self.assertEquals(response.status_code, 200) params = {'title': 'Hello Pycon', 'body': 'Text'} response = c.post('/posts/add/', params) self.assertEquals(response.status_code, 302) post = Post.objects.get(title=params['title'])
  • 40. Прочее в Django - Middleware - Template tags, filters - Context processors - тестируются модульными тестами как простые функции, аналогично с примером 1+1 = 2
  • 41. Особенности тестов view в Django ---------------------------- middleware ----------------------------- context processors ----------------------------- template ----------------------------- view ----------------------------- models ----------------------------- network
  • 42. Flexmock - Заменять части объектов и классов - Заменять функции, в том числе встроенные - Создавать объекты заглушки - Проверять ожидания (сколько раз вызван метод, с какими аргументами)
  • 43. $ pip install flexmock
  • 44. from flexmock import flexmock from blog.models import Post def test_home_page_with_flexmock(self): posts = [ Post(title='hello flexmock'), Post(title='hello flexmock'), ] (flexmock(Post.objects) .should_receive('all') .and_return(posts) .once()) response = self.client.get('/') self.assertEquals(response.status_code, 200) self.assertIn('hello flexmock', response.content)
  • 45. from flexmock import flexmock import blog.views def test_home_view_as_unittest(self): request = flexmock( GET={}, POST={}, META={'HTTP_HOST':'example.com'} ) response = blog.views.home(request) self.assertEquals(response.status_code, 200)
  • 47. Есть требования ... def get_url_content(url): # ToDo # Вернуть контент страницы # или None, в случае ошибки pass
  • 48. Как написать тест? def test_get_url_content(self): url = 'http://example.com' text = get_url_content(url) self.assertEquals(text, ???)
  • 49. Тестирование реализации Пишем тест имея представление о внутренностях def get_url_content(url): try: response = urllib.urlopen(url) content = response.read() response.close() except IOError: return None return content Неверно с точки зрения теории, удобно на практике
  • 50. Тест для случая нормального выполнения def test_get_url_content(self): url = 'http://example.com' response = StringIO("<html>") (flexmock(urllib) .should_receive('urlopen') .with_args(url) .and_return(response) .once()) text = get_url_content(url) self.assertEquals(text, "<html>")
  • 51. Тест в случае ошибки сети def test_get_url_content_on_ioerror(self): url = 'http://example.com' (flexmock(urllib) .should_receive('urlopen') .with_args(url) .and_raise(IOError("test exception")) .once()) text = get_url_content(url) self.assertEquals(text, None)
  • 53. Спасибо за внимание! Доклад подготовили Илья Шаляпин ishalyapin@gmail.com www.ishalyapin.ru www.bookradar.org bitbucket.org/ishalyapin github.com/un1t Евгений Генералов e.generalov@gmail.com github.com/generalov