Skip to content

Commit 33544a0

Browse files
committed
created django_use_model marker for testing unmanaged models;
cherry-picked from d466743
1 parent 8bd3d3e commit 33544a0

File tree

4 files changed

+103
-2
lines changed

4 files changed

+103
-2
lines changed

docs/helpers.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,32 @@ when trying to access the database.
9494
client('some-url-with-invalid-template-vars')
9595

9696

97+
``pytest.mark.django_use_model`` - force model creation for unmanaged models
98+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
99+
100+
.. py:function:: pytest.mark.django_use_model(model)
101+
102+
:type model: django model or list of django models
103+
:param model:
104+
Model or models to be created, should be used only with models that
105+
have ``Meta.managed = False``
106+
107+
This will create requested model(s) for the scope of the marker.
108+
Allows testing of unmanaged models that are normally not created.
109+
110+
.. note::
111+
112+
To access database you still have to request access by using
113+
``pytest.mark.django_db``
114+
115+
Example usage::
116+
117+
@pytest.mark.django_db
118+
@pytest.mark.django_use_model(Unmanaged)
119+
def test_unmanaged():
120+
assert Unmanaged.objects.count() >= 0
121+
122+
97123
Fixtures
98124
--------
99125

pytest_django/plugin.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ def pytest_load_initial_conftests(early_config, parser, args):
184184
'the `urls` attribute of Django `TestCase` objects. *modstr* is '
185185
'a string specifying the module of a URL config, e.g. '
186186
'"my_app.test_urls".')
187+
early_config.addinivalue_line(
188+
'markers',
189+
'django_use_model(model): force model creation, '
190+
'even for unmanaged models. Model(s) are deleted at the end of scope')
187191

188192
options = parser.parse_known_args(args)
189193

@@ -387,6 +391,48 @@ def _django_db_marker(request):
387391
getfixturevalue(request, 'db')
388392

389393

394+
@pytest.fixture(autouse=True)
395+
def _django_use_model(request):
396+
"""Implement ``django_use_model`` marker.
397+
398+
Marker creates unmanaged models that normally aren't created.
399+
Destroys it at the end of marked scope.
400+
401+
Note that you still need to use ``django_db`` marker before this one.
402+
The test unit should be decorated:
403+
404+
@pytest.mark.django_db
405+
@pytest.mark.django_use_model(model)
406+
407+
:model: ModelClass, one or many
408+
"""
409+
marker = request.keywords.get('django_use_model', None)
410+
if not marker:
411+
return
412+
from django.db import connection
413+
414+
model = request.getfuncargvalue('model')
415+
416+
if isinstance(model, (list, tuple)):
417+
models = model
418+
else:
419+
models = (model,)
420+
421+
with contextlib.closing(connection.schema_editor()) as schema:
422+
schema.deferred_sql = []
423+
for model_class in models:
424+
if not hasattr(model, '_meta'):
425+
raise ValueError('"model" must be a valid model class')
426+
schema.create_model(model_class)
427+
428+
def drop():
429+
with contextlib.closing(connection.schema_editor()) as schema:
430+
for model_class in models:
431+
schema.delete_model(model_class)
432+
433+
request.addfinalizer(drop)
434+
435+
390436
@pytest.fixture(autouse=True, scope='class')
391437
def _django_setup_unittest(request, django_db_blocker):
392438
"""Setup a django unittest, internal to pytest-django."""

pytest_django_test/app/models.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,10 @@ def __unicode__(self):
99

1010
def __str__(self):
1111
return self.name
12+
13+
14+
class Unmanaged(models.Model):
15+
name = models.CharField(max_length=100)
16+
17+
class Meta:
18+
managed = False

tests/test_database.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
from __future__ import with_statement
22

33
import pytest
4-
from django.db import connection
4+
from django.db import connection, DatabaseError
55
from django.test.testcases import connections_support_transactions
66

77
from pytest_django.pytest_compat import getfixturevalue
8-
from pytest_django_test.app.models import Item
8+
from pytest_django_test.app.models import Item, Unmanaged
99

1010

1111
def test_noaccess():
@@ -141,6 +141,28 @@ def test_transactions_enabled(self):
141141
assert not connection.in_atomic_block
142142

143143

144+
@pytest.mark.django_db
145+
class TestUseModel:
146+
"""Tests for django_use_model marker"""
147+
148+
def test_unmanaged_missing(self):
149+
"""Test that Unmanaged model is not created by default"""
150+
with pytest.raises(DatabaseError):
151+
# If table does not exists, django will raise DatabaseError
152+
# but the message will depend on the backend.
153+
# Probably nothing else can be asserted here.
154+
Unmanaged.objects.exists()
155+
156+
@pytest.mark.django_use_model(Unmanaged)
157+
def test_unmanaged_created(self):
158+
"""Make sure unmanaged models are created"""
159+
assert Unmanaged.objects.count() == 0
160+
161+
def test_unmanaged_destroyed(self):
162+
"""Test that Unmanaged model was destroyed after last use"""
163+
self.test_unmanaged_missing()
164+
165+
144166
def test_unittest_interaction(django_testdir):
145167
"Test that (non-Django) unittests cannot access the DB."
146168

0 commit comments

Comments
 (0)