Entertaining testing with
pytest
Roman Imankulov / @rdotpy / 21 Apr 2017
Slide 2
Slide 2 text
Why developers don’t
like writing tests?
Slide 3
Slide 3 text
Testing in Python is a religion
• Original sin
• Absolution through pain and suffering
• Mystical experience
Slide 4
Slide 4 text
Original sin
● Original sin — dynamic typing and duck typing
● As a result, a natural inclination of a Python
developer to create little and stupid mistakes
exposed as runtime errors
Slide 5
Slide 5 text
Absolution through pain and suffering
Boilerplate Code
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
...
def tearDown(self):
...
def testFoo(self):
...
Slide 6
Slide 6 text
Absolution through pain and suffering
Verbose asserts
self.assertEqual(foo, 1,
'foo is not equal to one')
Function returning a function
@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('pt')
...
Slide 29
Slide 29 text
Crazy things
Slide 30
Slide 30 text
Fixtures in a separate thread
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
Slide 31
Slide 31 text
More use cases for fixtures
• warnings: turn MySQL warnings to errors
• mock: initialize mockup objects
• freezegun: time management
• selenium: run a web driver
What else
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
Slide 34
Slide 34 text
What else
• pytest-sugar: beautiful output
• pytest-django: integration with Django
• pytest-xdist: parallel and distributed testing
Slide 35
Slide 35 text
What else
• tox: testing against different versions of
Python
• detox: the same, but in parallel
[tox]
envlist = py27,py35,py36
[testenv]
deps=pytest
commands=py.test