pip install pytest pytest-django pytest-covpy.testpy.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=longLancer seulement certains tests :
-k test_footests/bar/test_baz.py-m functional ou -m "not functional"--reuse-db--create-db
[pytest]
addopts = --reuse-db --x --pdb --tb=native
20 secondes économisées à chaque run, ça aussi c'est gratuit
@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
def pytest_collection_modifyitems(items):
for item in items:
item.keywords['django_db'] = pytest.mark.django_db
Tu l'aura voulu
--markers
[pytest]
markers =
functional: mark a test as functional.
Puis -m functional ou -m "not functional"
self.assertEqual(foo(), 2)
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
trop verbeux, et inutile ?
assert foo() == 2
File "/home/mathieu/tests/test_example.py", line 13, in test_bidon
assert foo() == 2
AssertionError: assert 1 == 2
+ where 1 = foo()
assert pytest == 'much better, innit?'
self.assertEqual({'foo': 1}, {'foo': 2, 'bar': 2})
AssertionError: {'foo': 1} != {'foo': 2, 'bar': 2}
- {'foo': 1}
+ {'bar': 2, 'foo': 2}
peut mieux faire
assert {'foo': 1} == {'foo': 2, 'bar': 2}
AssertionError: assert {'foo': 1} == {'bar': 2, 'foo': 2}
Differing items:
{'foo': 1} != {'foo': 2}
Right contains more items:
{'bar': 2}
C'est que le début, d'accord, d'accord
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
def test_view(rf, settings):
assert rf.get('/').path == '/'
settings.USE_TZ = True
assert settings.USE_TZ
abracadabra
Pour tester unitairement ses vues
@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
Spéciale dédicace Benoit Bryon
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
@pytest.mark.parametrize(("input", "expected"),
[("3+5", 8), ("2+4", 6)])
def test_eval(input, expected):
assert eval(input) == expected
y'a un peu plus, je vous le met quand même ?
@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
double rainbow all the way!
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-webtestpy.testwebtest 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 :
@pytest.fixture(scope='function')
def app(request):
wtm = django_webtest.WebTestMixin()
wtm._patch_settings()
request.addfinalizer(wtm._unpatch_settings)
return django_webtest.DjangoTestApp()
comment ça, qui a dit "ouh le gros hack !", qu'il se dénonce
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
class MyTestCase(WebTest):
csrf_checks = False
c'est pour ton bien, je te dis
def 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'
puisque je te dis que c'est mieux comme ça
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