-
Notifications
You must be signed in to change notification settings - Fork 347
Add initial approach to put Django's asserts into pytest's namespace. #97 #144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
35e5786
e2e54f7
a7b9372
f563cec
8da7215
be866f9
bad3b09
87d86d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,5 @@ def django_settings_is_configured(): | |
return True | ||
|
||
|
||
|
||
def get_django_version(): | ||
return __import__('django').VERSION |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,6 @@ | |
This plugin handles creating and destroying the test environment and | ||
test database and provides some useful text fixtures. | ||
""" | ||
|
||
import os | ||
|
||
import pytest | ||
|
@@ -13,7 +12,8 @@ | |
admin_client, rf, settings, live_server, | ||
_live_server_helper) | ||
|
||
from .lazy_django import skip_if_no_django, django_settings_is_configured | ||
from .lazy_django import skip_if_no_django, django_settings_is_configured, \ | ||
get_django_version | ||
|
||
|
||
(_django_db_setup, db, transactional_db, client, admin_client, rf, | ||
|
@@ -22,10 +22,71 @@ | |
|
||
SETTINGS_MODULE_ENV = 'DJANGO_SETTINGS_MODULE' | ||
CONFIGURATION_ENV = 'DJANGO_CONFIGURATION' | ||
|
||
DJANGO_ASSERTS = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add documentation / a comment here how to extract these, if you've used some tool / macro for this, please? Probably somehow by using your |
||
(1, 3): ('assertContains', 'assertFormError', 'assertNotContains', | ||
'assertNumQueries', 'assertQuerysetEqual', 'assertRedirects', | ||
'assertTemplateNotUsed', 'assertTemplateUsed'), | ||
(1, 4): ('assertContains', 'assertFieldOutput', 'assertFormError', | ||
'assertHTMLEqual', 'assertHTMLNotEqual', 'assertNotContains', | ||
'assertNumQueries', 'assertQuerysetEqual', 'assertRaisesMessage', | ||
'assertRedirects', 'assertTemplateNotUsed', 'assertTemplateUsed'), | ||
(1, 5): ('assertContains', 'assertFieldOutput', 'assertFormError', | ||
'assertHTMLEqual', 'assertHTMLNotEqual', 'assertInHTML', | ||
'assertJSONEqual', 'assertNotContains', 'assertNumQueries', | ||
'assertQuerysetEqual', 'assertRaisesMessage', 'assertRedirects', | ||
'assertTemplateNotUsed', 'assertTemplateUsed', 'assertXMLEqual', | ||
'assertXMLNotEqual'), | ||
(1, 6): ('assertContains', 'assertFieldOutput', 'assertFormError', | ||
'assertFormsetError', 'assertHTMLEqual', 'assertHTMLNotEqual', | ||
'assertInHTML', 'assertJSONEqual', 'assertNotContains', | ||
'assertNumQueries', 'assertQuerysetEqual', 'assertRaisesMessage', | ||
'assertRedirects', 'assertTemplateNotUsed', 'assertTemplateUsed', | ||
'assertXMLEqual', 'assertXMLNotEqual'), | ||
(1, 7): ('assertContains', 'assertFieldOutput', 'assertFormError', | ||
'assertFormsetError', 'assertHTMLEqual', 'assertHTMLNotEqual', | ||
'assertInHTML', 'assertJSONEqual', 'assertNotContains', | ||
'assertNumQueries', 'assertQuerysetEqual', 'assertRaisesMessage', | ||
'assertRedirects', 'assertTemplateNotUsed', 'assertTemplateUsed', | ||
'assertXMLEqual', 'assertXMLNotEqual'), | ||
(1, 8): ('assertContains', 'assertFieldOutput', 'assertFormError', | ||
'assertFormsetError', 'assertHTMLEqual', 'assertHTMLNotEqual', | ||
'assertInHTML', 'assertJSONEqual', 'assertJSONNotEqual', | ||
'assertNotContains', 'assertNumQueries', 'assertQuerysetEqual', | ||
'assertRaisesMessage', 'assertRedirects', 'assertTemplateNotUsed', | ||
'assertTemplateUsed', 'assertXMLEqual', 'assertXMLNotEqual') | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe it should be possible to collect these methods directly from django's SimpleTestCase, TestCase and TransactionTestCase classes rather than hardcoding. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem with dynamically collecting these names is that Django may not be fully loaded when pytest_namespace is called. |
||
|
||
################ pytest hooks ################ | ||
|
||
|
||
def populate_namespace(): | ||
def _wrapper(name): | ||
|
||
def assertion_func(*args, **kwargs): | ||
from django.test import TestCase as DjangoTestCase | ||
|
||
getattr(DjangoTestCase('run'), name)(*args, **kwargs) | ||
|
||
return assertion_func | ||
|
||
asserts = {} | ||
for name in DJANGO_ASSERTS[get_django_version()[:2]]: | ||
asserts[name] = _wrapper(name) | ||
|
||
return {'django': asserts} | ||
|
||
|
||
def pytest_namespace(): | ||
"""Make unittest assert methods available. | ||
This is useful for things such floating point checks with assertAlmostEqual. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/such/such as/ |
||
""" | ||
try: | ||
django_settings_is_configured() | ||
except AssertionError: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks odd. What assertion gets handled here, and why is this used to populate the namespace? |
||
return populate_namespace() | ||
return {} | ||
|
||
|
||
def pytest_addoption(parser): | ||
group = parser.getgroup('django') | ||
group._addoption('--reuse-db', | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# coding: utf-8 | ||
import inspect | ||
|
||
import pytest | ||
|
||
from pytest_django.lazy_django import get_django_version | ||
from pytest_django.plugin import DJANGO_ASSERTS | ||
|
||
|
||
def _get_actual_assertions_names(): | ||
""" | ||
Returns list with names of all assertion helpers in Django. | ||
""" | ||
from django.test import TestCase as DjangoTestCase | ||
from django.utils.unittest import TestCase as DefaultTestCase | ||
|
||
obj = DjangoTestCase('run') | ||
is_assert = lambda x: x.startswith('assert') and '_' not in x | ||
base_methods = [name for name, member in inspect.getmembers(DefaultTestCase) | ||
if is_assert(name)] | ||
|
||
return [name for name, member in inspect.getmembers(obj) | ||
if is_assert(name) and name not in base_methods] | ||
|
||
|
||
def test_django_asserts_available(): | ||
django_assertions = _get_actual_assertions_names() | ||
expected_assertions = DJANGO_ASSERTS[get_django_version()[:2]] | ||
assert not set(django_assertions) ^ set(expected_assertions) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will this provide a useful diff on failure? Otherwise a normal comparison might be better. Also |
||
|
||
for name in expected_assertions: | ||
assert hasattr(pytest.django, name) | ||
|
||
|
||
def test_sanity(admin_client): | ||
from pytest.django import assertContains | ||
|
||
response = admin_client.get('/admin-required/') | ||
|
||
assertContains(response, 'You are an admin') | ||
with pytest.raises(AssertionError): | ||
assertContains(response, 'Access denied') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better write this as
from ... import ( ... )
.See https://github.com/timothycrosley/isort for a nice tool to sort imports automatically.
I use the following command with Vim:
/cc @pelme