pip install pytest pytest-django pytest-cov
py.test
py.test est compatible avec votre code actuel
bah non, c'est pas plus compliqué--duration=10
-x
(ou --maxfail=n
)--pdb
--pastebin=failed
--showlocals --tb=long
Lancer seulement certains tests :
-k test_foo
tests/bar/
test_baz.py
-m functional
ou -m "not functional"
--reuse-db
--create-db
20 secondes économisées à chaque run, ça aussi c'est gratuit[pytest]
addopts = --reuse-db --x --pdb --tb=native
@pytest.mark.django_db
Autoriser, explicitement, l'accès à la BDD.
On écrit des tests unitaires, et dans la mesure du possible, rapides.
C'est pour ton bien, crois moi@pytest.mark.django_db
def test_avec_db(self): # fonction/méthode
@pytest.mark.django_db
class TestFoo(TestCase): # classe
pytestmark = pytest.mark.django_db # module
Si tu veux te tirer une balle dans le pied, tu peux
dans conftest.py
Tu l'aura vouludef pytest_collection_modifyitems(items):
for item in items:
item.keywords['django_db'] = pytest.mark.django_db
--markers
[pytest]
markers =
functional: mark a test as functional.
Puis -m functional
ou -m "not functional"
self.assertEqual(foo(), 2)
trop verbeux, et inutile ?File "/home/mathieu/tests/test_example.py", line 11, in test_bidon
self.assertEqual(foo(), 2)
File "/usr/lib64/python2.7/unittest/case.py", line 515, in assertEqual
assertion_func(first, second, msg=msg)
File "/usr/lib64/python2.7/unittest/case.py", line 508, in _baseAssertEqual
raise self.failureException(msg)
AssertionError: 1 != 2
assert foo() == 2
assert pytest == 'much better, innit?'File "/home/mathieu/tests/test_example.py", line 13, in test_bidon
assert foo() == 2
AssertionError: assert 1 == 2
+ where 1 = foo()
self.assertEqual({'foo': 1}, {'foo': 2, 'bar': 2})
peut mieux faireAssertionError: {'foo': 1} != {'foo': 2, 'bar': 2}
- {'foo': 1}
+ {'bar': 2, 'foo': 2}
assert {'foo': 1} == {'foo': 2, 'bar': 2}
C'est que le début, d'accord, d'accordAssertionError: assert {'foo': 1} == {'bar': 2, 'foo': 2}
Differing items:
{'foo': 1} != {'foo': 2}
Right contains more items:
{'bar': 2}
Au niveau global, dans le fichier pytest.ini : principalement pour la déclaration des « mark » et les options par défaut
Au niveau local, impacte le répertoire en cours et ses descendants, dans le fichier conftest.py : pour les fixtures, les plugins, les hooks
On parle pas du même impactLa partie (mal?)heureusement magique de py.test
abracadabradef test_view(rf, settings):
assert rf.get('/').path == '/'
settings.USE_TZ = True
assert settings.USE_TZ
Pour tester unitairement ses vues
Spéciale dédicace Benoit Bryon@pytest.fixture(scope='session')
def setup_view():
def _setup_view(view, request, *args, **kwargs):
view.request = request
view.args = args
view.kwargs = kwargs
return view
return _setup_view
setup_view
: tester unitairement ses vuesstubber
: pour des stub facilesstub_save
: pour tester Model.save() sans toucher à la BDDapp
: une application WebTestview
, user
, form
...Écrire une seule fois le test, le lancer avec plusieurs entrées
y'a un peu plus, je vous le met quand même ?@pytest.mark.parametrize(("input", "expected"),
[("3+5", 8), ("2+4", 6)])
def test_eval(input, expected):
assert eval(input) == expected
double rainbow all the way!@pytest.fixture(scope="module",
params=["merlinux.eu", "mail.python.org"])
def smtp(request):
smtp = smtplib.SMTP(request.param)
def fin():
smtp.close()
request.addfinalizer(fin)
return smtp
Par Ian Bicking, l'auteur entre autres de... pfouuu (pip, virtualenv, WebOb)
Un remplaçant au client de test de Django, qui fonctionne au niveau WSGI au lieu de HTTP
les gars de MIB avaient raisonpip install webtest django-webtest
py.test
webtest est compatible avec votre code actuel (ou presque)
ok, c'est pas tout à fait compatible, mais franchement, pas loinPour utiliser django-webtest avec py.test, créer la fixture :
comment ça, qui a dit "ouh le gros hack !", qu'il se dénonce@pytest.fixture(scope='function')
def app(request):
wtm = django_webtest.WebTestMixin()
wtm._patch_settings()
request.addfinalizer(wtm._unpatch_settings)
return django_webtest.DjangoTestApp()
status=404
ou status="*"
)environ['wsgi.errors']
Les validations de CSRF ne sont pas désactivés
Du coup, les raw post sont plus compliqués... heureusement qu'on en fait pas souvent
c'est pour ton bien, je te disclass MyTestCase(WebTest):
csrf_checks = False
puisque je te dis que c'est mieux comme çadef test_login(self)
form = self.app.get(reverse('auth_login')).form
form['username'] = 'foo'
form['password'] = 'bar'
res = form.submit().follow()
assert res.context['user'].username == 'foo'
click sur un lien dans une response suivant un pattern sur :
<a>
et </a>
)Exemple : res.click(href=reverse('login'))
Fournit une interface à la jQuery pour faire des requêtes
len(res.pyquery.find('.comment'))
res.pyquery.find('#foo')) == 'foo'
Juste magique quand on debug ses tests fonctionnels, a utiliser avec l'option --pdb
de py.test :
>>> res.showbrowser()
la première fois, j'ai failli m'évanouir, encore mieux que le screenshot
Plus aucune raison pour ne pas écrire de tests !
formation à py.test : http://www.merlinux.eu/~hpk/testing.pdf
ces slides : http://mathieu.agopian.info/presentations/2013_09_djangocong/
tu écris des tests on te dit