Skip to content

Commit 74011c3

Browse files
Jakub Owczarskitimb07
authored andcommitted
created django_use_model marker for testing unmanaged models;
cherry-picked from d466743
1 parent 211495b commit 74011c3

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 @@ on what marks are and for notes on using_ them.
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
@@ -175,6 +175,10 @@ def pytest_load_initial_conftests(early_config, parser, args):
175175
'the `urls` attribute of Django `TestCase` objects. *modstr* is '
176176
'a string specifying the module of a URL config, e.g. '
177177
'"my_app.test_urls".')
178+
early_config.addinivalue_line(
179+
'markers',
180+
'django_use_model(model): force model creation, '
181+
'even for unmanaged models. Model(s) are deleted at the end of scope')
178182

179183
options = parser.parse_known_args(args)
180184

@@ -375,6 +379,48 @@ def _django_db_marker(request):
375379
request.getfuncargvalue('db')
376380

377381

382+
@pytest.fixture(autouse=True)
383+
def _django_use_model(request):
384+
"""Implement ``django_use_model`` marker.
385+
386+
Marker creates unmanaged models that normally aren't created.
387+
Destroys it at the end of marked scope.
388+
389+
Note that you still need to use ``django_db`` marker before this one.
390+
The test unit should be decorated:
391+
392+
@pytest.mark.django_db
393+
@pytest.mark.django_use_model(model)
394+
395+
:model: ModelClass, one or many
396+
"""
397+
marker = request.keywords.get('django_use_model', None)
398+
if not marker:
399+
return
400+
from django.db import connection
401+
402+
model = request.getfuncargvalue('model')
403+
404+
if isinstance(model, (list, tuple)):
405+
models = model
406+
else:
407+
models = (model,)
408+
409+
with contextlib.closing(connection.schema_editor()) as schema:
410+
schema.deferred_sql = []
411+
for model_class in models:
412+
if not hasattr(model, '_meta'):
413+
raise ValueError('"model" must be a valid model class')
414+
schema.create_model(model_class)
415+
416+
def drop():
417+
with contextlib.closing(connection.schema_editor()) as schema:
418+
for model_class in models:
419+
schema.delete_model(model_class)
420+
421+
request.addfinalizer(drop)
422+
423+
378424
@pytest.fixture(autouse=True, scope='class')
379425
def _django_setup_unittest(request, _django_cursor_wrapper):
380426
"""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,10 +1,10 @@
11
from __future__ import with_statement
22

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

7-
from pytest_django_test.app.models import Item
7+
from pytest_django_test.app.models import Item, Unmanaged
88

99

1010
def noop_transactions():
@@ -164,6 +164,28 @@ def test_transactions_enabled(self):
164164
assert not noop_transactions()
165165

166166

167+
@pytest.mark.django_db
168+
class TestUseModel:
169+
"""Tests for django_use_model marker"""
170+
171+
def test_unmanaged_missing(self):
172+
"""Test that Unmanaged model is not created by default"""
173+
with pytest.raises(DatabaseError):
174+
# If table does not exists, django will raise DatabaseError
175+
# but the message will depend on the backend.
176+
# Probably nothing else can be asserted here.
177+
Unmanaged.objects.exists()
178+
179+
@pytest.mark.django_use_model(Unmanaged)
180+
def test_unmanaged_created(self):
181+
"""Make sure unmanaged models are created"""
182+
assert Unmanaged.objects.count() == 0
183+
184+
def test_unmanaged_destroyed(self):
185+
"""Test that Unmanaged model was destroyed after last use"""
186+
self.test_unmanaged_missing()
187+
188+
167189
def test_unittest_interaction(django_testdir):
168190
"Test that (non-Django) unittests cannot access the DB."
169191

0 commit comments

Comments
 (0)