From 35e57867af2a73b482715923e2f92d96bb1ccfef Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Sun, 27 Jul 2014 12:48:39 +0200 Subject: [PATCH 1/7] Add initial approach to put Django's asserts into pytest's namespace --- pytest_django/lazy_django.py | 2 +- pytest_django/plugin.py | 28 ++++++++++++++++++++++++++-- tests/test_namespaces.py | 14 ++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 tests/test_namespaces.py diff --git a/pytest_django/lazy_django.py b/pytest_django/lazy_django.py index 217e5e4ed..65b1527fc 100644 --- a/pytest_django/lazy_django.py +++ b/pytest_django/lazy_django.py @@ -28,7 +28,7 @@ def django_settings_is_configured(): except (ImproperlyConfigured, ImportError): e = sys.exc_info()[1] raise pytest.UsageError( - "pytest_django: failed to load Django settings: %s" % (e.args)) + "pytest_django: failed to load Django settings: %s" % e.args) return settings.configured diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index bb91d5727..b608980e3 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -3,9 +3,8 @@ This plugin handles creating and destroying the test environment and test database and provides some useful text fixtures. """ - +import inspect import os -import sys import pytest @@ -28,6 +27,31 @@ ################ pytest hooks ################ +def pytest_namespace(): + """Make unittest assert methods available. + This is useful for things such floating point checks with assertAlmostEqual. + """ + try: + if django_settings_is_configured(): + from django.test import SimpleTestCase + from unittest import TestCase + + obj = SimpleTestCase('run') + is_assert = lambda x: x.startswith('assert') and '_' not in x + + base_methods = [name for name, member in inspect.getmembers(TestCase) + if is_assert(name)] + + names = {name: member + for name, member in inspect.getmembers(obj) + if is_assert(name) and name not in base_methods} + + return {'django': names} + except pytest.UsageError: + return {} + return {} + + def pytest_addoption(parser): group = parser.getgroup('django') group._addoption('--reuse-db', diff --git a/tests/test_namespaces.py b/tests/test_namespaces.py new file mode 100644 index 000000000..d00586c2c --- /dev/null +++ b/tests/test_namespaces.py @@ -0,0 +1,14 @@ +# coding: utf-8 +import pytest + + +def test_django_asserts_available(): + assert hasattr(pytest.django, 'assertTemplateUsed') + + +def test_sanity(): + from pytest.django import assertJSONEqual + + assertJSONEqual('{}', '{}') + with pytest.raises(AssertionError): + assertJSONEqual('{}', '{"a": "1"}') From e2e54f7c82fdb543b2d691cee3a0c82e98d45514 Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Sun, 27 Jul 2014 21:34:16 +0200 Subject: [PATCH 2/7] Fix python 2.6 compatibility --- pytest_django/plugin.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index b608980e3..5016d3063 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -42,9 +42,9 @@ def pytest_namespace(): base_methods = [name for name, member in inspect.getmembers(TestCase) if is_assert(name)] - names = {name: member - for name, member in inspect.getmembers(obj) - if is_assert(name) and name not in base_methods} + names = dict((name, member) + for name, member in inspect.getmembers(obj) + if is_assert(name) and name not in base_methods) return {'django': names} except pytest.UsageError: From f563cec98038da54d5ded9b64310947c54c69670 Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Mon, 28 Jul 2014 13:58:55 +0200 Subject: [PATCH 3/7] Add list of Django's assertions, fix namespace loading, add assertions wrappers --- pytest_django/lazy_django.py | 1 - pytest_django/plugin.py | 59 +++++++++++++++++++++++++----------- tests/test_namespaces.py | 32 ++++++++++++++----- 3 files changed, 66 insertions(+), 26 deletions(-) diff --git a/pytest_django/lazy_django.py b/pytest_django/lazy_django.py index ee003b544..ae7f10467 100644 --- a/pytest_django/lazy_django.py +++ b/pytest_django/lazy_django.py @@ -24,6 +24,5 @@ def django_settings_is_configured(): return True - def get_django_version(): return __import__('django').VERSION diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index cf6bbeab5..0d976d5c6 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -3,7 +3,6 @@ This plugin handles creating and destroying the test environment and test database and provides some useful text fixtures. """ -import inspect 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,33 +22,56 @@ SETTINGS_MODULE_ENV = 'DJANGO_SETTINGS_MODULE' CONFIGURATION_ENV = 'DJANGO_CONFIGURATION' - +DJANGO_ASSERTS = { + (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'), +} ################ pytest hooks ################ + def pytest_namespace(): """Make unittest assert methods available. This is useful for things such floating point checks with assertAlmostEqual. """ - try: - if django_settings_is_configured(): - from django.test import SimpleTestCase - from unittest import TestCase - obj = SimpleTestCase('run') - is_assert = lambda x: x.startswith('assert') and '_' not in x + def _wrapper(name): + + def assertion_func(*args, **kwargs): + from django.test import TestCase as DjangoTestCase + + getattr(DjangoTestCase('run'), name)(*args, **kwargs) - base_methods = [name for name, member in inspect.getmembers(TestCase) - if is_assert(name)] + return assertion_func - names = dict((name, member) - for name, member in inspect.getmembers(obj) - if is_assert(name) and name not in base_methods) + asserts = {} + for name in DJANGO_ASSERTS[get_django_version()[:2]]: + asserts[name] = _wrapper(name) - return {'django': names} - except pytest.UsageError: - return {} - return {} + return {'django': asserts} def pytest_addoption(parser): diff --git a/tests/test_namespaces.py b/tests/test_namespaces.py index d00586c2c..d1067c4c7 100644 --- a/tests/test_namespaces.py +++ b/tests/test_namespaces.py @@ -1,14 +1,32 @@ # coding: utf-8 +import inspect + import pytest +from pytest_django.lazy_django import get_django_version +from pytest_django.plugin import DJANGO_ASSERTS -def test_django_asserts_available(): - assert hasattr(pytest.django, 'assertTemplateUsed') +def _get_actual_assertions_names(): + """ + Returns list with names of all assertion helpers in Django. + """ + from django.test import TestCase as DjangoTestCase + from 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)] -def test_sanity(): - from pytest.django import assertJSONEqual + 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) - assertJSONEqual('{}', '{}') - with pytest.raises(AssertionError): - assertJSONEqual('{}', '{"a": "1"}') + for name in expected_assertions: + assert hasattr(pytest.django, name) From 8da7215e31373251304ac310fe2ecd806184246c Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Mon, 28 Jul 2014 14:09:45 +0200 Subject: [PATCH 4/7] Fix for test configurations without Django loaded --- pytest_django/plugin.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index 0d976d5c6..7800f3c64 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -53,11 +53,7 @@ ################ pytest hooks ################ -def pytest_namespace(): - """Make unittest assert methods available. - This is useful for things such floating point checks with assertAlmostEqual. - """ - +def populate_namespace(): def _wrapper(name): def assertion_func(*args, **kwargs): @@ -74,6 +70,17 @@ def assertion_func(*args, **kwargs): return {'django': asserts} +def pytest_namespace(): + """Make unittest assert methods available. + This is useful for things such floating point checks with assertAlmostEqual. + """ + try: + django_settings_is_configured() + except AssertionError: + return populate_namespace() + return {} + + def pytest_addoption(parser): group = parser.getgroup('django') group._addoption('--reuse-db', From be866f964912641299537c895312564a24ec57b5 Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Mon, 28 Jul 2014 15:28:31 +0200 Subject: [PATCH 5/7] Add assertions name for Django 1.8 --- pytest_django/plugin.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py index 7800f3c64..9b482f209 100644 --- a/pytest_django/plugin.py +++ b/pytest_django/plugin.py @@ -44,10 +44,16 @@ 'assertXMLEqual', 'assertXMLNotEqual'), (1, 7): ('assertContains', 'assertFieldOutput', 'assertFormError', 'assertFormsetError', 'assertHTMLEqual', 'assertHTMLNotEqual', - 'assertInHTML', 'assertJSONEqual', 'assertNotContains', 'assertNumQueries', - 'assertQuerysetEqual', 'assertRaisesMessage', 'assertRedirects', - 'assertTemplateNotUsed', 'assertTemplateUsed', 'assertXMLEqual', - 'assertXMLNotEqual'), + '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') } ################ pytest hooks ################ From bad3b09cd517651026def3f46967a141c6fd28e9 Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Mon, 28 Jul 2014 16:03:51 +0200 Subject: [PATCH 6/7] Change import to be able to use backported unittest module on python 2.6 --- tests/test_namespaces.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_namespaces.py b/tests/test_namespaces.py index d1067c4c7..7015eb4bf 100644 --- a/tests/test_namespaces.py +++ b/tests/test_namespaces.py @@ -12,7 +12,7 @@ def _get_actual_assertions_names(): Returns list with names of all assertion helpers in Django. """ from django.test import TestCase as DjangoTestCase - from unittest import TestCase as DefaultTestCase + from django.utils.unittest import TestCase as DefaultTestCase obj = DjangoTestCase('run') is_assert = lambda x: x.startswith('assert') and '_' not in x From 87d86d63afc6e840a2b4a5633a6d2408349422bc Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Mon, 28 Jul 2014 16:27:09 +0200 Subject: [PATCH 7/7] Add sanity test for Django's assertions --- tests/test_namespaces.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_namespaces.py b/tests/test_namespaces.py index 7015eb4bf..481080bdc 100644 --- a/tests/test_namespaces.py +++ b/tests/test_namespaces.py @@ -30,3 +30,13 @@ def test_django_asserts_available(): 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')