Skip to content
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

Add support for testing unmanaged models #600

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/helpers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,32 @@ when trying to access the database.
client('some-url-with-invalid-template-vars')


``pytest.mark.django_use_model`` - force model creation for unmanaged models
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. py:function:: pytest.mark.django_use_model(model=ModelClass)

:type model: django model or list of django models, as kwarg
:param model:
Model or models to be created, should be used only with models that
have ``Meta.managed = False``

This will create requested model(s) for the scope of the marker.
Allows testing of unmanaged models that are normally not created.

.. note::

To access database you still have to request access by using
``pytest.mark.django_db``

Example usage::

@pytest.mark.django_db
@pytest.mark.django_use_model(model=Unmanaged)
def test_unmanaged():
assert Unmanaged.objects.count() >= 0


Fixtures
--------

Expand Down
46 changes: 46 additions & 0 deletions pytest_django/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ def pytest_load_initial_conftests(early_config, parser, args):
'the `urls` attribute of Django `TestCase` objects. *modstr* is '
'a string specifying the module of a URL config, e.g. '
'"my_app.test_urls".')
early_config.addinivalue_line(
'markers',
'django_use_model(model=ModelClass): force model creation, '
'even for unmanaged models. Model(s) are deleted at the end of scope')

options = parser.parse_known_args(args)

Expand Down Expand Up @@ -387,6 +391,48 @@ def _django_db_marker(request):
getfixturevalue(request, 'db')


@pytest.fixture(autouse=True)
def _django_use_model(request):
"""Implement ``django_use_model`` marker.

Marker creates unmanaged models that normally aren't created.
Destroys it at the end of marked scope.

Note that you still need to use ``django_db`` marker before this one.
The test unit should be decorated:

@pytest.mark.django_db
@pytest.mark.django_use_model(model=ModelClass)

:model: ModelClass, one or many
"""
marker = request.keywords.get('django_use_model', None)
if not marker:
return
from django.db import connection

model = marker.kwargs['model']

if isinstance(model, (list, tuple)):
models = model
else:
models = (model,)

with connection.schema_editor() as schema:
schema.deferred_sql = []
for model_class in models:
if not hasattr(model, '_meta'):
raise ValueError('"model" must be a valid model class')
schema.create_model(model_class)

def drop():
with connection.schema_editor() as schema:
for model_class in models:
schema.delete_model(model_class)

request.addfinalizer(drop)


@pytest.fixture(autouse=True, scope='class')
def _django_setup_unittest(request, django_db_blocker):
"""Setup a django unittest, internal to pytest-django."""
Expand Down
7 changes: 7 additions & 0 deletions pytest_django_test/app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,10 @@ def __unicode__(self):

def __str__(self):
return self.name


class Unmanaged(models.Model):
name = models.CharField(max_length=100)

class Meta:
managed = False
28 changes: 26 additions & 2 deletions tests/test_database.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from __future__ import with_statement

import pytest
from django.db import connection
from django.db import connection, DatabaseError
from django.test.testcases import connections_support_transactions

from pytest_django.pytest_compat import getfixturevalue
from pytest_django_test.app.models import Item
from pytest_django_test.app.models import Item, Unmanaged


def test_noaccess():
Expand Down Expand Up @@ -141,6 +141,30 @@ def test_transactions_enabled(self):
assert not connection.in_atomic_block


@pytest.mark.skipif(not hasattr(connection, 'schema_editor'),
reason="This Django version does not support SchemaEditor")
@pytest.mark.django_db
class TestUseModel:
"""Tests for django_use_model marker"""

def test_unmanaged_missing(self):
"""Test that Unmanaged model is not created by default"""
with pytest.raises(DatabaseError):
# If table does not exists, django will raise DatabaseError
# but the message will depend on the backend.
# Probably nothing else can be asserted here.
Unmanaged.objects.exists()

@pytest.mark.django_use_model(model=Unmanaged)
def test_unmanaged_created(self):
"""Make sure unmanaged models are created"""
assert Unmanaged.objects.count() == 0

def test_unmanaged_destroyed(self):
"""Test that Unmanaged model was destroyed after last use"""
self.test_unmanaged_missing()


def test_unittest_interaction(django_testdir):
"Test that (non-Django) unittests cannot access the DB."

Expand Down