O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.
Нескучное тестирование
с pytest
Роман Иманкулов / @rdotpy / 27 июня 2014
Почему программисты
не любят писать тесты?
Тестирование в Python — это
религия
• Врождённая греховность
• Очищение через страдание
• Мистический опыт
Врождённая греховность
 Врожденные пороки — нестрогая типизация и duck
typing
• Как следствие — природная склонность прог...
Очищение через страдание
Boilerplate Code
    class TestSequenceFunctions(unittest.TestCase):
        def setUp(self):
   ...
Очищение через страдание
Многословные ассерты
    
    self.assertEqual(foo, 1, 
                     'foo is not equal to...
Мистический опыт
Django testing setups & teardowns
Есть ли альтернатива?
pytest
pytest — это не еще один
xUnit фреймворк!
pytest fixtures
То, что отличает pytest
от других фреймворков
pytest fixtures
Наивный подход. Как это бы сделал я сам
file: fixtures.py
    def get_user():
        return User(name='Ro...
pytest fixtures
Подход pytest
file: conftest.py
    @pytest.fixture
    def user():
        return User(name='Roman', age=...
Зависимости между fixtures
@pytest.fixture
def user():
    return User(name='Roman', age=30, ...)       
@pytest.fixture
def task(user):
    return T...
Fixture dependencies. Patching object
@pytest.fixture
def premium(user)
    user.set_premium()
def test_premium(user, prem...
yield_fixture
setup и teardown
в одном флаконе
@pytest.yield_fixture
def user():
    obj = User(name='Roman', age=30, ...)       
    yield obj
    obj.delete()
Fixture scopes
• function scope
• module scope
• session scope
Session fixture. Локальный кеш
@pytest.yield_fixture(scope='session', autouse=True)
def local_cache():
    old_settings = ...
Function fixture.
Database transaction rollback
@pytest.yield_fixture
def tx():
    db().start_transaction()
    yield
   ...
Session fixture. Чистый redis
@pytest.yield_fixture(scope='session')
def redis_server():
    proc = subp.Popen(['redis­ser...
fixtures parametrization
Функция возвращает функцию
@pytest.fixture
def set_lang(user):
    def func(lang_code):    
        user.set_lang(lang_cod...
Странные вещи
Fixtures в отдельном потоке
http://bit.ly/test_pool
@pytest.fixture(scope='session')
def item_gen():
    gen = Generator(l...
Как ещё использовать fixtures
• warnings: turn MySQL warnings to errors
• mock: подготовка mockup объектов
• freezegun: уп...
О чём я ещё не рассказал
def pytest_addoption(parser):
    parser.addoption("­­clean­mysql",
  action="store_true", defaul...
О чём я ещё не рассказал
@pytest.mark.parametrize("input,expected", [
    ("3+5", 8),
    ("2+4", 6),
])
def test_eval(inp...
О чём я ещё не рассказал
• pytest-django: интеграция с Django
• pytest-xdist: параллельные и
распределенные тесты
О чём я ещё не рассказал
• tox: выполнение тестов для разных python
• detox: то же самое, только параллельно
[tox]
envlist...
Спасибо! Вопросы?
Роман Иманкулов / @rdotpy / http://imankulov.name
Нескучное тестирование с pytest
Нескучное тестирование с pytest
Próximos SlideShares
Carregando em…5
×

Нескучное тестирование с pytest

9.518 visualizações

Publicada em

Написание юнит-тестов большинству представляется занятием скучным и до некоторой степени бесполезным. Мое мнение — это всё оттого, что сама "классическая" схема юнит-тестов подразумевает непродуктивное написание унылого линейного кода.

В докладе я расскажу о том, как с помощью pytest начать писать тесты, которые приятно читать и поддерживать, почему setUp и tearDown — это прошлый век, как с помощью правильной организации fixtures ускорить исполнение тестов, а также какие ещё уловки могут помочь вам в вашей нелегкой борьбе с рутиной.

Publicada em: Software
  • Seja o primeiro a comentar

Нескучное тестирование с pytest

  1. 1. Нескучное тестирование с pytest Роман Иманкулов / @rdotpy / 27 июня 2014
  2. 2. Почему программисты не любят писать тесты?
  3. 3. Тестирование в Python — это религия • Врождённая греховность • Очищение через страдание • Мистический опыт
  4. 4. Врождённая греховность  Врожденные пороки — нестрогая типизация и duck typing • Как следствие — природная склонность программиста на Python к совершению маленьких и глупых ошибок
  5. 5. Очищение через страдание Boilerplate Code     class TestSequenceFunctions(unittest.TestCase):         def setUp(self):             ...         def tearDown(self):             ...         def testFoo(self):             ...
  6. 6. Очищение через страдание Многословные ассерты          self.assertEqual(foo, 1,                       'foo is not equal to one')
  7. 7. Мистический опыт Django testing setups & teardowns
  8. 8. Есть ли альтернатива?
  9. 9. pytest
  10. 10. pytest — это не еще один xUnit фреймворк!
  11. 11. pytest fixtures То, что отличает pytest от других фреймворков
  12. 12. pytest fixtures Наивный подход. Как это бы сделал я сам file: fixtures.py     def get_user():         return User(name='Roman', age=30, ...)         file: test_user.py     def test_user():         user = get_user()         assert user.name == 'Roman'
  13. 13. pytest fixtures Подход pytest file: conftest.py     @pytest.fixture     def user():         return User(name='Roman', age=30, ...)         file: test_user.py     def test_user(user):         assert user.name == 'Roman'
  14. 14. Зависимости между fixtures
  15. 15. @pytest.fixture def user():     return User(name='Roman', age=30, ...)        @pytest.fixture def task(user):     return Task(user=user, name='...') def test_task(task):     assert task.user.name == 'Roman'
  16. 16. Fixture dependencies. Patching object @pytest.fixture def premium(user)     user.set_premium() def test_premium(user, premium):     assert user.is_premum()
  17. 17. yield_fixture setup и teardown в одном флаконе
  18. 18. @pytest.yield_fixture def user():     obj = User(name='Roman', age=30, ...)            yield obj     obj.delete()
  19. 19. Fixture scopes • function scope • module scope • session scope
  20. 20. Session fixture. Локальный кеш @pytest.yield_fixture(scope='session', autouse=True) def local_cache():     old_settings = settings.CACHES     settings.CACHES = {'default': {…}}     yield     settings.CACHES = old_settings
  21. 21. Function fixture. Database transaction rollback @pytest.yield_fixture def tx():     db().start_transaction()     yield     db().rollback() def test_user(user, tx, project, task):     # project & task will be removed automatically
  22. 22. Session fixture. Чистый redis @pytest.yield_fixture(scope='session') def redis_server():     proc = subp.Popen(['redis­server', '­­port', 7777], ... )     yield proc     proc.terminate() @pytest.fixture def rc(redis_server):     client = redis.StrictRedis('redis://127.0.0.1:7777')     client.flushall()     return client
  23. 23. fixtures parametrization
  24. 24. Функция возвращает функцию @pytest.fixture def set_lang(user):     def func(lang_code):             user.set_lang(lang_code)     return func def test_languages(user, set_lang):     set_lang('ru')     ...
  25. 25. Странные вещи
  26. 26. Fixtures в отдельном потоке http://bit.ly/test_pool @pytest.fixture(scope='session') def item_gen():     gen = Generator(lambda: .)     gen.start()     return gen @pytest.yield_fixture def item(item_gen, item_rel):     item = item_gen.get()     yield item     item_rel.put(item) @pytest.fixture(scope='session') def item_rel():     rel = Releaser(lambda o: ...)     rel.start()     return rel
  27. 27. Как ещё использовать fixtures • warnings: turn MySQL warnings to errors • mock: подготовка mockup объектов • freezegun: управление временем • selenium: запуск веб-драйвера
  28. 28. О чём я ещё не рассказал def pytest_addoption(parser):     parser.addoption("­­clean­mysql",   action="store_true", default=False) @pytest.fixture(scope='session', autouse=True) def clean_mysql(request):     if not request.config.getoption('­­clean­mysql'):            return      # clean MySQL tables heres
  29. 29. О чём я ещё не рассказал @pytest.mark.parametrize("input,expected", [     ("3+5", 8),     ("2+4", 6), ]) def test_eval(input, expected):     assert eval(input) == expected
  30. 30. О чём я ещё не рассказал • pytest-django: интеграция с Django • pytest-xdist: параллельные и распределенные тесты
  31. 31. О чём я ещё не рассказал • tox: выполнение тестов для разных python • detox: то же самое, только параллельно [tox] envlist = py26,py27 [testenv] deps=pytest   commands=py.test
  32. 32. Спасибо! Вопросы? Роман Иманкулов / @rdotpy / http://imankulov.name

×