Support for running the test suite with py.test

* Get rid of runtests.py
 * Moved test code  from rest_framework/tests and rest_framework/runtests to tests
 * Invoke py.test from setup.py
 * Invoke py.test from Travis
 * Invoke py.test from tox
 * Changed setUpClass to be just plain setUp in test_permissions.py
 * Updated contribution guideline to show how to invoke py.test
This commit is contained in:
Andreas Pelme 2014-03-02 12:40:30 +01:00
parent 62786a7ad6
commit 971578ca34
73 changed files with 206 additions and 251 deletions

View File

@ -15,6 +15,7 @@ env:
install: install:
- pip install $DJANGO - pip install $DJANGO
- pip install defusedxml==0.3 - pip install defusedxml==0.3
- pip install pytest-django==2.6
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install oauth2==1.5.211; fi" - "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install oauth2==1.5.211; fi"
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth-plus==2.2.1; fi" - "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth-plus==2.2.1; fi"
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth2-provider==0.2.4; fi" - "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth2-provider==0.2.4; fi"
@ -24,7 +25,7 @@ install:
- export PYTHONPATH=. - export PYTHONPATH=.
script: script:
- python rest_framework/runtests/runtests.py - py.test
matrix: matrix:
exclude: exclude:

View File

@ -65,7 +65,7 @@ To run the tests, clone the repository, and then:
pip install -r optionals.txt pip install -r optionals.txt
# Run the tests # Run the tests
rest_framework/runtests/runtests.py py.test
You can also use the excellent [`tox`][tox] testing tool to run the tests against all supported versions of Python and Django. Install `tox` globally, and then simply run: You can also use the excellent [`tox`][tox] testing tool to run the tests against all supported versions of Python and Django. Install `tox` globally, and then simply run:

85
conftest.py Normal file
View File

@ -0,0 +1,85 @@
def pytest_configure():
from django.conf import settings
settings.configure(
DEBUG_PROPAGATE_EXCEPTIONS=True,
DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:'}},
SECRET_KEY='not very secret in tests',
USE_I18N=True,
USE_L10N=True,
STATIC_URL='/static/',
ROOT_URLCONF='tests.urls',
TEMPLATE_LOADERS=(
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
),
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
),
INSTALLED_APPS=(
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'rest_framework',
'rest_framework.authtoken',
'tests',
'tests.accounts',
'tests.records',
'tests.users',
),
PASSWORD_HASHERS=(
'django.contrib.auth.hashers.SHA1PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
'django.contrib.auth.hashers.MD5PasswordHasher',
'django.contrib.auth.hashers.CryptPasswordHasher',
),
)
try:
import oauth_provider
import oauth2
except ImportError:
pass
else:
settings.INSTALLED_APPS += (
'oauth_provider',
)
try:
import provider
except ImportError:
pass
else:
settings.INSTALLED_APPS += (
'provider',
'provider.oauth2',
)
# guardian is optional
try:
import guardian
except ImportError:
pass
else:
settings.ANONYMOUS_USER_ID = -1
settings.AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', # default
'guardian.backends.ObjectPermissionBackend',
)
settings.INSTALLED_APPS += (
'guardian',
)
# Force Django to load all models
from django.db.models import get_models
get_models()

View File

@ -206,19 +206,9 @@ General guides to using REST framework.
## Development ## Development
If you want to work on REST framework itself, clone the repository, then... See the [Contribution guidelines][contributing] for information on how to clone
the repository, run the test suite and contribute changes back to REST
Build the docs: Framework.
./mkdocs.py
Run the tests:
./rest_framework/runtests/runtests.py
To run the tests against all supported configurations, first install [the tox testing tool][tox] globally, using `pip install tox`, then simply run `tox`:
tox
## Support ## Support

View File

@ -65,7 +65,7 @@ To run the tests, clone the repository, and then:
pip install -r optionals.txt pip install -r optionals.txt
# Run the tests # Run the tests
rest_framework/runtests/runtests.py py.test
You can also use the excellent `[tox][tox]` testing tool to run the tests against all supported versions of Python and Django. Install `tox` globally, and then simply run: You can also use the excellent `[tox][tox]` testing tool to run the tests against all supported versions of Python and Django. Install `tox` globally, and then simply run:

2
pytest.ini Normal file
View File

@ -0,0 +1,2 @@
[pytest]
addopts = --tb=short

View File

@ -1 +1,3 @@
-e .
Django>=1.3 Django>=1.3
pytest-django==2.6

View File

@ -1,78 +0,0 @@
#!/usr/bin/env python
"""
Useful tool to run the test suite for rest_framework and generate a coverage report.
"""
# http://ericholscher.com/blog/2009/jun/29/enable-setuppy-test-your-django-apps/
# http://www.travisswicegood.com/2010/01/17/django-virtualenv-pip-and-fabric/
# http://code.djangoproject.com/svn/django/trunk/tests/runtests.py
import os
import sys
# fix sys path so we don't need to setup PYTHONPATH
sys.path.append(os.path.join(os.path.dirname(__file__), "../.."))
os.environ['DJANGO_SETTINGS_MODULE'] = 'rest_framework.runtests.settings'
from coverage import coverage
def main():
"""Run the tests for rest_framework and generate a coverage report."""
cov = coverage()
cov.erase()
cov.start()
from django.conf import settings
from django.test.utils import get_runner
TestRunner = get_runner(settings)
if hasattr(TestRunner, 'func_name'):
# Pre 1.2 test runners were just functions,
# and did not support the 'failfast' option.
import warnings
warnings.warn(
'Function-based test runners are deprecated. Test runners should be classes with a run_tests() method.',
DeprecationWarning
)
failures = TestRunner(['tests'])
else:
test_runner = TestRunner()
failures = test_runner.run_tests(['tests'])
cov.stop()
# Discover the list of all modules that we should test coverage for
import rest_framework
project_dir = os.path.dirname(rest_framework.__file__)
cov_files = []
for (path, dirs, files) in os.walk(project_dir):
# Drop tests and runtests directories from the test coverage report
if os.path.basename(path) in ['tests', 'runtests', 'migrations']:
continue
# Drop the compat and six modules from coverage, since we're not interested in the coverage
# of modules which are specifically for resolving environment dependant imports.
# (Because we'll end up getting different coverage reports for it for each environment)
if 'compat.py' in files:
files.remove('compat.py')
if 'six.py' in files:
files.remove('six.py')
# Same applies to template tags module.
# This module has to include branching on Django versions,
# so it's never possible for it to have full coverage.
if 'rest_framework.py' in files:
files.remove('rest_framework.py')
cov_files.extend([os.path.join(path, file) for file in files if file.endswith('.py')])
cov.report(cov_files)
if '--html' in sys.argv:
cov.html_report(cov_files, directory='coverage')
sys.exit(failures)
if __name__ == '__main__':
main()

View File

@ -1,48 +0,0 @@
#!/usr/bin/env python
# http://ericholscher.com/blog/2009/jun/29/enable-setuppy-test-your-django-apps/
# http://www.travisswicegood.com/2010/01/17/django-virtualenv-pip-and-fabric/
# http://code.djangoproject.com/svn/django/trunk/tests/runtests.py
import os
import sys
# fix sys path so we don't need to setup PYTHONPATH
sys.path.append(os.path.join(os.path.dirname(__file__), "../.."))
os.environ['DJANGO_SETTINGS_MODULE'] = 'rest_framework.runtests.settings'
import django
from django.conf import settings
from django.test.utils import get_runner
def usage():
return """
Usage: python runtests.py [UnitTestClass].[method]
You can pass the Class name of the `UnitTestClass` you want to test.
Append a method name if you only want to test a specific method of that class.
"""
def main():
TestRunner = get_runner(settings)
test_runner = TestRunner()
if len(sys.argv) == 2:
test_case = '.' + sys.argv[1]
elif len(sys.argv) == 1:
test_case = ''
else:
print(usage())
sys.exit(1)
test_module_name = 'rest_framework.tests'
if django.VERSION[0] == 1 and django.VERSION[1] < 6:
test_module_name = 'tests'
failures = test_runner.run_tests([test_module_name + test_case])
sys.exit(failures)
if __name__ == '__main__':
main()

View File

@ -1,7 +0,0 @@
"""
Blank URLConf just to keep runtests.py happy.
"""
from rest_framework.compat import patterns
urlpatterns = patterns('',
)

View File

@ -1,16 +0,0 @@
"""
Force import of all modules in this package in order to get the standard test
runner to pick up the tests. Yowzers.
"""
from __future__ import unicode_literals
import os
import django
modules = [filename.rsplit('.', 1)[0]
for filename in os.listdir(os.path.dirname(__file__))
if filename.endswith('.py') and not filename.startswith('_')]
__test__ = dict()
if django.VERSION < (1, 6):
for module in modules:
exec("from rest_framework.tests.%s import *" % module)

View File

@ -2,11 +2,26 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from setuptools import setup from setuptools import setup
from setuptools.command.test import test as TestCommand
import re import re
import os import os
import sys import sys
# This command has been borrowed from
# https://github.com/getsentry/sentry/blob/master/setup.py
class PyTest(TestCommand):
def finalize_options(self):
TestCommand.finalize_options(self)
self.test_args = ['tests']
self.test_suite = True
def run_tests(self):
import pytest
errno = pytest.main(self.test_args)
sys.exit(errno)
def get_version(package): def get_version(package):
""" """
Return package version as listed in `__version__` in `init.py`. Return package version as listed in `__version__` in `init.py`.
@ -62,7 +77,7 @@ setup(
author_email='tom@tomchristie.com', # SEE NOTE BELOW (*) author_email='tom@tomchristie.com', # SEE NOTE BELOW (*)
packages=get_packages('rest_framework'), packages=get_packages('rest_framework'),
package_data=get_package_data('rest_framework'), package_data=get_package_data('rest_framework'),
test_suite='rest_framework.runtests.runtests.main', cmdclass={'test': PyTest},
install_requires=[], install_requires=[],
classifiers=[ classifiers=[
'Development Status :: 5 - Production/Stable', 'Development Status :: 5 - Production/Stable',

View File

@ -1,6 +1,6 @@
from django.db import models from django.db import models
from rest_framework.tests.users.models import User from tests.users.models import User
class Account(models.Model): class Account(models.Model):

View File

@ -1,7 +1,7 @@
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.accounts.models import Account from tests.accounts.models import Account
from rest_framework.tests.users.serializers import UserSerializer from tests.users.serializers import UserSerializer
class AccountSerializer(serializers.ModelSerializer): class AccountSerializer(serializers.ModelSerializer):

View File

@ -1,6 +1,6 @@
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.models import NullableForeignKeySource from tests.models import NullableForeignKeySource
class NullableFKSourceSerializer(serializers.ModelSerializer): class NullableFKSourceSerializer(serializers.ModelSerializer):

View File

@ -79,7 +79,7 @@ MIDDLEWARE_CLASSES = (
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
) )
ROOT_URLCONF = 'urls' ROOT_URLCONF = 'tests.urls'
TEMPLATE_DIRS = ( TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
@ -99,10 +99,10 @@ INSTALLED_APPS = (
# 'django.contrib.admindocs', # 'django.contrib.admindocs',
'rest_framework', 'rest_framework',
'rest_framework.authtoken', 'rest_framework.authtoken',
'rest_framework.tests', 'tests',
'rest_framework.tests.accounts', 'tests.accounts',
'rest_framework.tests.records', 'tests.records',
'rest_framework.tests.users', 'tests.users',
) )
# OAuth is optional and won't work if there is no oauth_provider & oauth2 # OAuth is optional and won't work if there is no oauth_provider & oauth2

View File

@ -64,7 +64,7 @@ if oauth2_provider is not None:
class BasicAuthTests(TestCase): class BasicAuthTests(TestCase):
"""Basic authentication""" """Basic authentication"""
urls = 'rest_framework.tests.test_authentication' urls = 'tests.test_authentication'
def setUp(self): def setUp(self):
self.csrf_client = APIClient(enforce_csrf_checks=True) self.csrf_client = APIClient(enforce_csrf_checks=True)
@ -103,7 +103,7 @@ class BasicAuthTests(TestCase):
class SessionAuthTests(TestCase): class SessionAuthTests(TestCase):
"""User session authentication""" """User session authentication"""
urls = 'rest_framework.tests.test_authentication' urls = 'tests.test_authentication'
def setUp(self): def setUp(self):
self.csrf_client = APIClient(enforce_csrf_checks=True) self.csrf_client = APIClient(enforce_csrf_checks=True)
@ -150,7 +150,7 @@ class SessionAuthTests(TestCase):
class TokenAuthTests(TestCase): class TokenAuthTests(TestCase):
"""Token authentication""" """Token authentication"""
urls = 'rest_framework.tests.test_authentication' urls = 'tests.test_authentication'
def setUp(self): def setUp(self):
self.csrf_client = APIClient(enforce_csrf_checks=True) self.csrf_client = APIClient(enforce_csrf_checks=True)
@ -244,7 +244,7 @@ class IncorrectCredentialsTests(TestCase):
class OAuthTests(TestCase): class OAuthTests(TestCase):
"""OAuth 1.0a authentication""" """OAuth 1.0a authentication"""
urls = 'rest_framework.tests.test_authentication' urls = 'tests.test_authentication'
def setUp(self): def setUp(self):
# these imports are here because oauth is optional and hiding them in try..except block or compat # these imports are here because oauth is optional and hiding them in try..except block or compat
@ -474,7 +474,7 @@ class OAuthTests(TestCase):
class OAuth2Tests(TestCase): class OAuth2Tests(TestCase):
"""OAuth 2.0 authentication""" """OAuth 2.0 authentication"""
urls = 'rest_framework.tests.test_authentication' urls = 'tests.test_authentication'
def setUp(self): def setUp(self):
self.csrf_client = APIClient(enforce_csrf_checks=True) self.csrf_client = APIClient(enforce_csrf_checks=True)

View File

@ -36,7 +36,7 @@ urlpatterns = patterns('',
class BreadcrumbTests(TestCase): class BreadcrumbTests(TestCase):
"""Tests the breadcrumb functionality used by the HTML renderer.""" """Tests the breadcrumb functionality used by the HTML renderer."""
urls = 'rest_framework.tests.test_breadcrumbs' urls = 'tests.test_breadcrumbs'
def test_root_breadcrumbs(self): def test_root_breadcrumbs(self):
url = '/' url = '/'

View File

@ -4,8 +4,8 @@ from __future__ import unicode_literals
from django.test import TestCase from django.test import TestCase
from rest_framework.compat import apply_markdown, smart_text from rest_framework.compat import apply_markdown, smart_text
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.tests.description import ViewWithNonASCIICharactersInDocstring from .description import ViewWithNonASCIICharactersInDocstring
from rest_framework.tests.description import UTF8_TEST_DOCSTRING from .description import UTF8_TEST_DOCSTRING
# We check that docstrings get nicely un-indented. # We check that docstrings get nicely un-indented.
DESCRIPTION = """an example docstring DESCRIPTION = """an example docstring

View File

@ -11,7 +11,7 @@ from django.db import models
from django.test import TestCase from django.test import TestCase
from django.utils.datastructures import SortedDict from django.utils.datastructures import SortedDict
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.models import RESTFrameworkModel from tests.models import RESTFrameworkModel
class TimestampedModel(models.Model): class TimestampedModel(models.Model):

View File

@ -8,7 +8,7 @@ from django.utils import unittest
from rest_framework import generics, serializers, status, filters from rest_framework import generics, serializers, status, filters
from rest_framework.compat import django_filters, patterns, url from rest_framework.compat import django_filters, patterns, url
from rest_framework.test import APIRequestFactory from rest_framework.test import APIRequestFactory
from rest_framework.tests.models import BasicModel from tests.models import BasicModel
factory = APIRequestFactory() factory = APIRequestFactory()
@ -243,7 +243,7 @@ class IntegrationTestDetailFiltering(CommonFilteringTestCase):
""" """
Integration tests for filtered detail views. Integration tests for filtered detail views.
""" """
urls = 'rest_framework.tests.test_filters' urls = 'tests.test_filters'
def _get_url(self, item): def _get_url(self, item):
return reverse('detail-view', kwargs=dict(pk=item.pk)) return reverse('detail-view', kwargs=dict(pk=item.pk))
@ -612,4 +612,4 @@ class SensitiveOrderingFilterTests(TestCase):
{'id': 2, username_field: 'userB'}, # PassC {'id': 2, username_field: 'userB'}, # PassC
{'id': 3, username_field: 'userC'}, # PassA {'id': 3, username_field: 'userC'}, # PassA
] ]
) )

View File

@ -4,7 +4,7 @@ from django.shortcuts import get_object_or_404
from django.test import TestCase from django.test import TestCase
from rest_framework import generics, renderers, serializers, status from rest_framework import generics, renderers, serializers, status
from rest_framework.test import APIRequestFactory from rest_framework.test import APIRequestFactory
from rest_framework.tests.models import BasicModel, Comment, SlugBasedModel from tests.models import BasicModel, Comment, SlugBasedModel
from rest_framework.compat import six from rest_framework.compat import six
factory = APIRequestFactory() factory = APIRequestFactory()

View File

@ -42,7 +42,7 @@ urlpatterns = patterns('',
class TemplateHTMLRendererTests(TestCase): class TemplateHTMLRendererTests(TestCase):
urls = 'rest_framework.tests.test_htmlrenderer' urls = 'tests.test_htmlrenderer'
def setUp(self): def setUp(self):
""" """
@ -82,7 +82,7 @@ class TemplateHTMLRendererTests(TestCase):
class TemplateHTMLRendererExceptionTests(TestCase): class TemplateHTMLRendererExceptionTests(TestCase):
urls = 'rest_framework.tests.test_htmlrenderer' urls = 'tests.test_htmlrenderer'
def setUp(self): def setUp(self):
""" """

View File

@ -5,7 +5,7 @@ from rest_framework import generics, status, serializers
from rest_framework.compat import patterns, url from rest_framework.compat import patterns, url
from rest_framework.settings import api_settings from rest_framework.settings import api_settings
from rest_framework.test import APIRequestFactory from rest_framework.test import APIRequestFactory
from rest_framework.tests.models import ( from tests.models import (
Anchor, BasicModel, ManyToManyModel, BlogPost, BlogPostComment, Anchor, BasicModel, ManyToManyModel, BlogPost, BlogPostComment,
Album, Photo, OptionalRelationModel Album, Photo, OptionalRelationModel
) )
@ -110,7 +110,7 @@ urlpatterns = patterns('',
class TestBasicHyperlinkedView(TestCase): class TestBasicHyperlinkedView(TestCase):
urls = 'rest_framework.tests.test_hyperlinkedserializers' urls = 'tests.test_hyperlinkedserializers'
def setUp(self): def setUp(self):
""" """
@ -147,7 +147,7 @@ class TestBasicHyperlinkedView(TestCase):
class TestManyToManyHyperlinkedView(TestCase): class TestManyToManyHyperlinkedView(TestCase):
urls = 'rest_framework.tests.test_hyperlinkedserializers' urls = 'tests.test_hyperlinkedserializers'
def setUp(self): def setUp(self):
""" """
@ -195,7 +195,7 @@ class TestManyToManyHyperlinkedView(TestCase):
class TestHyperlinkedIdentityFieldLookup(TestCase): class TestHyperlinkedIdentityFieldLookup(TestCase):
urls = 'rest_framework.tests.test_hyperlinkedserializers' urls = 'tests.test_hyperlinkedserializers'
def setUp(self): def setUp(self):
""" """
@ -225,7 +225,7 @@ class TestHyperlinkedIdentityFieldLookup(TestCase):
class TestCreateWithForeignKeys(TestCase): class TestCreateWithForeignKeys(TestCase):
urls = 'rest_framework.tests.test_hyperlinkedserializers' urls = 'tests.test_hyperlinkedserializers'
def setUp(self): def setUp(self):
""" """
@ -250,7 +250,7 @@ class TestCreateWithForeignKeys(TestCase):
class TestCreateWithForeignKeysAndCustomSlug(TestCase): class TestCreateWithForeignKeysAndCustomSlug(TestCase):
urls = 'rest_framework.tests.test_hyperlinkedserializers' urls = 'tests.test_hyperlinkedserializers'
def setUp(self): def setUp(self):
""" """
@ -275,7 +275,7 @@ class TestCreateWithForeignKeysAndCustomSlug(TestCase):
class TestOptionalRelationHyperlinkedView(TestCase): class TestOptionalRelationHyperlinkedView(TestCase):
urls = 'rest_framework.tests.test_hyperlinkedserializers' urls = 'tests.test_hyperlinkedserializers'
def setUp(self): def setUp(self):
""" """
@ -335,7 +335,7 @@ class TestOverriddenURLField(TestCase):
class TestURLFieldNameBySettings(TestCase): class TestURLFieldNameBySettings(TestCase):
urls = 'rest_framework.tests.test_hyperlinkedserializers' urls = 'tests.test_hyperlinkedserializers'
def setUp(self): def setUp(self):
self.saved_url_field_name = api_settings.URL_FIELD_NAME self.saved_url_field_name = api_settings.URL_FIELD_NAME
@ -360,7 +360,7 @@ class TestURLFieldNameBySettings(TestCase):
class TestURLFieldNameByOptions(TestCase): class TestURLFieldNameByOptions(TestCase):
urls = 'rest_framework.tests.test_hyperlinkedserializers' urls = 'tests.test_hyperlinkedserializers'
def setUp(self): def setUp(self):
class Serializer(serializers.HyperlinkedModelSerializer): class Serializer(serializers.HyperlinkedModelSerializer):

View File

@ -2,7 +2,7 @@ from __future__ import unicode_literals
from django.db import models from django.db import models
from django.test import TestCase from django.test import TestCase
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.models import RESTFrameworkModel from tests.models import RESTFrameworkModel
# Models # Models

View File

@ -2,9 +2,9 @@ from django.core.urlresolvers import reverse
from rest_framework.compat import patterns, url from rest_framework.compat import patterns, url
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
from rest_framework.tests.models import NullableForeignKeySource from tests.models import NullableForeignKeySource
from rest_framework.tests.serializers import NullableFKSourceSerializer from tests.serializers import NullableFKSourceSerializer
from rest_framework.tests.views import NullableFKSourceDetail from tests.views import NullableFKSourceDetail
urlpatterns = patterns( urlpatterns = patterns(
@ -18,7 +18,7 @@ class NullableForeignKeyTests(APITestCase):
DRF should be able to handle nullable foreign keys when a test DRF should be able to handle nullable foreign keys when a test
Client POST/PUT request is made with its own serialized object. Client POST/PUT request is made with its own serialized object.
""" """
urls = 'rest_framework.tests.test_nullable_fields' urls = 'tests.test_nullable_fields'
def test_updating_object_with_null_fk(self): def test_updating_object_with_null_fk(self):
obj = NullableForeignKeySource(name='example', target=None) obj = NullableForeignKeySource(name='example', target=None)

View File

@ -8,7 +8,7 @@ from django.utils import unittest
from rest_framework import generics, status, pagination, filters, serializers from rest_framework import generics, status, pagination, filters, serializers
from rest_framework.compat import django_filters from rest_framework.compat import django_filters
from rest_framework.test import APIRequestFactory from rest_framework.test import APIRequestFactory
from rest_framework.tests.models import BasicModel from tests.models import BasicModel
factory = APIRequestFactory() factory = APIRequestFactory()

View File

@ -7,7 +7,7 @@ from rest_framework import generics, status, permissions, authentication, HTTP_H
from rest_framework.compat import guardian, get_model_name from rest_framework.compat import guardian, get_model_name
from rest_framework.filters import DjangoObjectPermissionsFilter from rest_framework.filters import DjangoObjectPermissionsFilter
from rest_framework.test import APIRequestFactory from rest_framework.test import APIRequestFactory
from rest_framework.tests.models import BasicModel from tests.models import BasicModel
import base64 import base64
factory = APIRequestFactory() factory = APIRequestFactory()
@ -187,8 +187,7 @@ class ObjectPermissionsIntegrationTests(TestCase):
""" """
Integration tests for the object level permissions API. Integration tests for the object level permissions API.
""" """
@classmethod def setUp(self):
def setUpClass(cls):
from guardian.shortcuts import assign_perm from guardian.shortcuts import assign_perm
# create users # create users
@ -215,21 +214,13 @@ class ObjectPermissionsIntegrationTests(TestCase):
assign_perm(perm, everyone) assign_perm(perm, everyone)
everyone.user_set.add(*users.values()) everyone.user_set.add(*users.values())
cls.perms = perms
cls.users = users
def setUp(self):
from guardian.shortcuts import assign_perm
perms = self.perms
users = self.users
# appropriate object level permissions # appropriate object level permissions
readers = Group.objects.create(name='readers') readers = Group.objects.create(name='readers')
writers = Group.objects.create(name='writers') writers = Group.objects.create(name='writers')
deleters = Group.objects.create(name='deleters') deleters = Group.objects.create(name='deleters')
model = BasicPermModel.objects.create(text='foo') model = BasicPermModel.objects.create(text='foo')
assign_perm(perms['view'], readers, model) assign_perm(perms['view'], readers, model)
assign_perm(perms['change'], writers, model) assign_perm(perms['change'], writers, model)
assign_perm(perms['delete'], deleters, model) assign_perm(perms['delete'], deleters, model)

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
from django.db import models from django.db import models
from django.test import TestCase from django.test import TestCase
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.models import BlogPost from tests.models import BlogPost
class NullModel(models.Model): class NullModel(models.Model):
@ -105,7 +105,7 @@ class RelatedFieldSourceTests(TestCase):
Check that the exception message are correct if the source field Check that the exception message are correct if the source field
doesn't exist. doesn't exist.
""" """
from rest_framework.tests.models import ManyToManySource from tests.models import ManyToManySource
class Meta: class Meta:
model = ManyToManySource model = ManyToManySource
attrs = { attrs = {

View File

@ -3,7 +3,7 @@ from django.test import TestCase
from rest_framework import serializers from rest_framework import serializers
from rest_framework.compat import patterns, url from rest_framework.compat import patterns, url
from rest_framework.test import APIRequestFactory from rest_framework.test import APIRequestFactory
from rest_framework.tests.models import ( from tests.models import (
BlogPost, BlogPost,
ManyToManyTarget, ManyToManySource, ForeignKeyTarget, ForeignKeySource, ManyToManyTarget, ManyToManySource, ForeignKeyTarget, ForeignKeySource,
NullableForeignKeySource, OneToOneTarget, NullableOneToOneSource NullableForeignKeySource, OneToOneTarget, NullableOneToOneSource
@ -71,7 +71,7 @@ class NullableOneToOneTargetSerializer(serializers.HyperlinkedModelSerializer):
# TODO: Add test that .data cannot be accessed prior to .is_valid # TODO: Add test that .data cannot be accessed prior to .is_valid
class HyperlinkedManyToManyTests(TestCase): class HyperlinkedManyToManyTests(TestCase):
urls = 'rest_framework.tests.test_relations_hyperlink' urls = 'tests.test_relations_hyperlink'
def setUp(self): def setUp(self):
for idx in range(1, 4): for idx in range(1, 4):
@ -179,7 +179,7 @@ class HyperlinkedManyToManyTests(TestCase):
class HyperlinkedForeignKeyTests(TestCase): class HyperlinkedForeignKeyTests(TestCase):
urls = 'rest_framework.tests.test_relations_hyperlink' urls = 'tests.test_relations_hyperlink'
def setUp(self): def setUp(self):
target = ForeignKeyTarget(name='target-1') target = ForeignKeyTarget(name='target-1')
@ -307,7 +307,7 @@ class HyperlinkedForeignKeyTests(TestCase):
class HyperlinkedNullableForeignKeyTests(TestCase): class HyperlinkedNullableForeignKeyTests(TestCase):
urls = 'rest_framework.tests.test_relations_hyperlink' urls = 'tests.test_relations_hyperlink'
def setUp(self): def setUp(self):
target = ForeignKeyTarget(name='target-1') target = ForeignKeyTarget(name='target-1')
@ -435,7 +435,7 @@ class HyperlinkedNullableForeignKeyTests(TestCase):
class HyperlinkedNullableOneToOneTests(TestCase): class HyperlinkedNullableOneToOneTests(TestCase):
urls = 'rest_framework.tests.test_relations_hyperlink' urls = 'tests.test_relations_hyperlink'
def setUp(self): def setUp(self):
target = OneToOneTarget(name='target-1') target = OneToOneTarget(name='target-1')
@ -458,7 +458,7 @@ class HyperlinkedNullableOneToOneTests(TestCase):
# Regression tests for #694 (`source` attribute on related fields) # Regression tests for #694 (`source` attribute on related fields)
class HyperlinkedRelatedFieldSourceTests(TestCase): class HyperlinkedRelatedFieldSourceTests(TestCase):
urls = 'rest_framework.tests.test_relations_hyperlink' urls = 'tests.test_relations_hyperlink'
def test_related_manager_source(self): def test_related_manager_source(self):
""" """

View File

@ -2,7 +2,7 @@ from __future__ import unicode_literals
from django.db import models from django.db import models
from django.test import TestCase from django.test import TestCase
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.models import ( from tests.models import (
BlogPost, ManyToManyTarget, ManyToManySource, ForeignKeyTarget, ForeignKeySource, BlogPost, ManyToManyTarget, ManyToManySource, ForeignKeyTarget, ForeignKeySource,
NullableForeignKeySource, OneToOneTarget, NullableOneToOneSource, NullableForeignKeySource, OneToOneTarget, NullableOneToOneSource,
) )

View File

@ -1,6 +1,6 @@
from django.test import TestCase from django.test import TestCase
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.models import NullableForeignKeySource, ForeignKeySource, ForeignKeyTarget from tests.models import NullableForeignKeySource, ForeignKeySource, ForeignKeyTarget
class ForeignKeyTargetSerializer(serializers.ModelSerializer): class ForeignKeyTargetSerializer(serializers.ModelSerializer):

View File

@ -152,7 +152,7 @@ class RendererEndToEndTests(TestCase):
End-to-end testing of renderers using an RendererMixin on a generic view. End-to-end testing of renderers using an RendererMixin on a generic view.
""" """
urls = 'rest_framework.tests.test_renderers' urls = 'tests.test_renderers'
def test_default_renderer_serializes_content(self): def test_default_renderer_serializes_content(self):
"""If the Accept header is not set the default renderer should serialize the response.""" """If the Accept header is not set the default renderer should serialize the response."""
@ -387,7 +387,7 @@ class JSONPRendererTests(TestCase):
Tests specific to the JSONP Renderer Tests specific to the JSONP Renderer
""" """
urls = 'rest_framework.tests.test_renderers' urls = 'tests.test_renderers'
def test_without_callback_with_json_renderer(self): def test_without_callback_with_json_renderer(self):
""" """
@ -571,7 +571,7 @@ class CacheRenderTest(TestCase):
Tests specific to caching responses Tests specific to caching responses
""" """
urls = 'rest_framework.tests.test_renderers' urls = 'tests.test_renderers'
cache_key = 'just_a_cache_key' cache_key = 'just_a_cache_key'

View File

@ -278,7 +278,7 @@ urlpatterns = patterns('',
class TestContentParsingWithAuthentication(TestCase): class TestContentParsingWithAuthentication(TestCase):
urls = 'rest_framework.tests.test_request' urls = 'tests.test_request'
def setUp(self): def setUp(self):
self.csrf_client = APIClient(enforce_csrf_checks=True) self.csrf_client = APIClient(enforce_csrf_checks=True)

View File

@ -1,6 +1,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.test import TestCase from django.test import TestCase
from rest_framework.tests.models import BasicModel, BasicModelSerializer from tests.models import BasicModel, BasicModelSerializer
from rest_framework.compat import patterns, url, include from rest_framework.compat import patterns, url, include
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
@ -118,7 +118,7 @@ class RendererIntegrationTests(TestCase):
End-to-end testing of renderers using an ResponseMixin on a generic view. End-to-end testing of renderers using an ResponseMixin on a generic view.
""" """
urls = 'rest_framework.tests.test_response' urls = 'tests.test_response'
def test_default_renderer_serializes_content(self): def test_default_renderer_serializes_content(self):
"""If the Accept header is not set the default renderer should serialize the response.""" """If the Accept header is not set the default renderer should serialize the response."""
@ -198,7 +198,7 @@ class Issue122Tests(TestCase):
""" """
Tests that covers #122. Tests that covers #122.
""" """
urls = 'rest_framework.tests.test_response' urls = 'tests.test_response'
def test_only_html_renderer(self): def test_only_html_renderer(self):
""" """
@ -218,7 +218,7 @@ class Issue467Tests(TestCase):
Tests for #467 Tests for #467
""" """
urls = 'rest_framework.tests.test_response' urls = 'tests.test_response'
def test_form_has_label_and_help_text(self): def test_form_has_label_and_help_text(self):
resp = self.client.get('/html_new_model') resp = self.client.get('/html_new_model')
@ -232,7 +232,7 @@ class Issue807Tests(TestCase):
Covers #807 Covers #807
""" """
urls = 'rest_framework.tests.test_response' urls = 'tests.test_response'
def test_does_not_append_charset_by_default(self): def test_does_not_append_charset_by_default(self):
""" """

View File

@ -19,7 +19,7 @@ class ReverseTests(TestCase):
""" """
Tests for fully qualified URLs when using `reverse`. Tests for fully qualified URLs when using `reverse`.
""" """
urls = 'rest_framework.tests.test_reverse' urls = 'tests.test_reverse'
def test_reversed_urls_are_fully_qualified(self): def test_reversed_urls_are_fully_qualified(self):
request = factory.get('/view') request = factory.get('/view')

View File

@ -72,7 +72,7 @@ class TestCustomLookupFields(TestCase):
""" """
Ensure that custom lookup fields are correctly routed. Ensure that custom lookup fields are correctly routed.
""" """
urls = 'rest_framework.tests.test_routers' urls = 'tests.test_routers'
def setUp(self): def setUp(self):
class NoteSerializer(serializers.HyperlinkedModelSerializer): class NoteSerializer(serializers.HyperlinkedModelSerializer):
@ -91,7 +91,7 @@ class TestCustomLookupFields(TestCase):
self.router = SimpleRouter() self.router = SimpleRouter()
self.router.register(r'notes', NoteViewSet) self.router.register(r'notes', NoteViewSet)
from rest_framework.tests import test_routers from tests import test_routers
urls = getattr(test_routers, 'urlpatterns') urls = getattr(test_routers, 'urlpatterns')
urls += patterns('', urls += patterns('',
url(r'^', include(self.router.urls)), url(r'^', include(self.router.urls)),

View File

@ -6,10 +6,10 @@ from django.test import TestCase
from django.utils.datastructures import MultiValueDict from django.utils.datastructures import MultiValueDict
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers, fields, relations from rest_framework import serializers, fields, relations
from rest_framework.tests.models import (HasPositiveIntegerAsChoice, Album, ActionItem, Anchor, BasicModel, from tests.models import (HasPositiveIntegerAsChoice, Album, ActionItem, Anchor, BasicModel,
BlankFieldModel, BlogPost, BlogPostComment, Book, CallableDefaultValueModel, DefaultValueModel, BlankFieldModel, BlogPost, BlogPostComment, Book, CallableDefaultValueModel, DefaultValueModel,
ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo, RESTFrameworkModel) ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo, RESTFrameworkModel)
from rest_framework.tests.models import BasicModelSerializer from tests.models import BasicModelSerializer
import datetime import datetime
import pickle import pickle
@ -1034,7 +1034,7 @@ class RelatedTraversalTest(TestCase):
""" """
If a component of the dotted.source is None, return None for the field. If a component of the dotted.source is None, return None for the field.
""" """
from rest_framework.tests.models import NullableForeignKeySource from tests.models import NullableForeignKeySource
instance = NullableForeignKeySource.objects.create(name='Source with null FK') instance = NullableForeignKeySource.objects.create(name='Source with null FK')
class NullableSourceSerializer(serializers.Serializer): class NullableSourceSerializer(serializers.Serializer):

View File

@ -1,7 +1,7 @@
from django.test import TestCase from django.test import TestCase
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.accounts.serializers import AccountSerializer from tests.accounts.serializers import AccountSerializer
class ImportingModelSerializerTests(TestCase): class ImportingModelSerializerTests(TestCase):

View File

@ -2,7 +2,7 @@ from django.db import models
from django.test import TestCase from django.test import TestCase
from rest_framework.serializers import _resolve_model from rest_framework.serializers import _resolve_model
from rest_framework.tests.models import BasicModel from tests.models import BasicModel
class ResolveModelTests(TestCase): class ResolveModelTests(TestCase):

View File

@ -10,13 +10,13 @@ class TestSettings(TestCase):
def test_non_import_errors(self): def test_non_import_errors(self):
"""Make sure other errors aren't suppressed.""" """Make sure other errors aren't suppressed."""
settings = APISettings({'DEFAULT_MODEL_SERIALIZER_CLASS': 'rest_framework.tests.extras.bad_import.ModelSerializer'}, DEFAULTS, IMPORT_STRINGS) settings = APISettings({'DEFAULT_MODEL_SERIALIZER_CLASS': 'tests.extras.bad_import.ModelSerializer'}, DEFAULTS, IMPORT_STRINGS)
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
settings.DEFAULT_MODEL_SERIALIZER_CLASS settings.DEFAULT_MODEL_SERIALIZER_CLASS
def test_import_error_message_maintained(self): def test_import_error_message_maintained(self):
"""Make sure real import errors are captured and raised sensibly.""" """Make sure real import errors are captured and raised sensibly."""
settings = APISettings({'DEFAULT_MODEL_SERIALIZER_CLASS': 'rest_framework.tests.extras.not_here.ModelSerializer'}, DEFAULTS, IMPORT_STRINGS) settings = APISettings({'DEFAULT_MODEL_SERIALIZER_CLASS': 'tests.extras.not_here.ModelSerializer'}, DEFAULTS, IMPORT_STRINGS)
with self.assertRaises(ImportError) as cm: with self.assertRaises(ImportError) as cm:
settings.DEFAULT_MODEL_SERIALIZER_CLASS settings.DEFAULT_MODEL_SERIALIZER_CLASS
self.assertTrue('ImportError' in str(cm.exception)) self.assertTrue('ImportError' in str(cm.exception))

View File

@ -35,7 +35,7 @@ urlpatterns = patterns('',
class TestAPITestClient(TestCase): class TestAPITestClient(TestCase):
urls = 'rest_framework.tests.test_testing' urls = 'tests.test_testing'
def setUp(self): def setUp(self):
self.client = APIClient() self.client = APIClient()

6
tests/urls.py Normal file
View File

@ -0,0 +1,6 @@
"""
Blank URLConf just to keep the test suite happy
"""
from rest_framework.compat import patterns
urlpatterns = patterns('')

View File

@ -1,6 +1,6 @@
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.users.models import User from tests.users.models import User
class UserSerializer(serializers.ModelSerializer): class UserSerializer(serializers.ModelSerializer):

View File

@ -1,6 +1,6 @@
from rest_framework import generics from rest_framework import generics
from rest_framework.tests.models import NullableForeignKeySource from .models import NullableForeignKeySource
from rest_framework.tests.serializers import NullableFKSourceSerializer from .serializers import NullableFKSourceSerializer
class NullableFKSourceDetail(generics.RetrieveUpdateDestroyAPIView): class NullableFKSourceDetail(generics.RetrieveUpdateDestroyAPIView):

14
tox.ini
View File

@ -3,19 +3,21 @@ downloadcache = {toxworkdir}/cache/
envlist = py3.3-django1.6,py3.2-django1.6,py2.7-django1.6,py2.6-django1.6,py3.3-django1.5,py3.2-django1.5,py2.7-django1.5,py2.6-django1.5,py2.7-django1.4,py2.6-django1.4,py2.7-django1.3,py2.6-django1.3 envlist = py3.3-django1.6,py3.2-django1.6,py2.7-django1.6,py2.6-django1.6,py3.3-django1.5,py3.2-django1.5,py2.7-django1.5,py2.6-django1.5,py2.7-django1.4,py2.6-django1.4,py2.7-django1.3,py2.6-django1.3
[testenv] [testenv]
commands = {envpython} rest_framework/runtests/runtests.py commands = py.test -q
[testenv:py3.3-django1.6] [testenv:py3.3-django1.6]
basepython = python3.3 basepython = python3.3
deps = Django==1.6 deps = Django==1.6
django-filter==0.6a1 django-filter==0.6a1
defusedxml==0.3 defusedxml==0.3
pytest-django==2.6
[testenv:py3.2-django1.6] [testenv:py3.2-django1.6]
basepython = python3.2 basepython = python3.2
deps = Django==1.6 deps = Django==1.6
django-filter==0.6a1 django-filter==0.6a1
defusedxml==0.3 defusedxml==0.3
pytest-django==2.6
[testenv:py2.7-django1.6] [testenv:py2.7-django1.6]
basepython = python2.7 basepython = python2.7
@ -26,6 +28,7 @@ deps = Django==1.6
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.4 django-oauth2-provider==0.2.4
django-guardian==1.1.1 django-guardian==1.1.1
pytest-django==2.6
[testenv:py2.6-django1.6] [testenv:py2.6-django1.6]
basepython = python2.6 basepython = python2.6
@ -36,18 +39,21 @@ deps = Django==1.6
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.4 django-oauth2-provider==0.2.4
django-guardian==1.1.1 django-guardian==1.1.1
pytest-django==2.6
[testenv:py3.3-django1.5] [testenv:py3.3-django1.5]
basepython = python3.3 basepython = python3.3
deps = django==1.5.5 deps = django==1.5.5
django-filter==0.6a1 django-filter==0.6a1
defusedxml==0.3 defusedxml==0.3
pytest-django==2.6
[testenv:py3.2-django1.5] [testenv:py3.2-django1.5]
basepython = python3.2 basepython = python3.2
deps = django==1.5.5 deps = django==1.5.5
django-filter==0.6a1 django-filter==0.6a1
defusedxml==0.3 defusedxml==0.3
pytest-django==2.6
[testenv:py2.7-django1.5] [testenv:py2.7-django1.5]
basepython = python2.7 basepython = python2.7
@ -58,6 +64,7 @@ deps = django==1.5.5
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.3 django-oauth2-provider==0.2.3
django-guardian==1.1.1 django-guardian==1.1.1
pytest-django==2.6
[testenv:py2.6-django1.5] [testenv:py2.6-django1.5]
basepython = python2.6 basepython = python2.6
@ -68,6 +75,7 @@ deps = django==1.5.5
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.3 django-oauth2-provider==0.2.3
django-guardian==1.1.1 django-guardian==1.1.1
pytest-django==2.6
[testenv:py2.7-django1.4] [testenv:py2.7-django1.4]
basepython = python2.7 basepython = python2.7
@ -78,6 +86,7 @@ deps = django==1.4.10
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.3 django-oauth2-provider==0.2.3
django-guardian==1.1.1 django-guardian==1.1.1
pytest-django==2.6
[testenv:py2.6-django1.4] [testenv:py2.6-django1.4]
basepython = python2.6 basepython = python2.6
@ -88,6 +97,7 @@ deps = django==1.4.10
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.3 django-oauth2-provider==0.2.3
django-guardian==1.1.1 django-guardian==1.1.1
pytest-django==2.6
[testenv:py2.7-django1.3] [testenv:py2.7-django1.3]
basepython = python2.7 basepython = python2.7
@ -98,6 +108,7 @@ deps = django==1.3.5
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.3 django-oauth2-provider==0.2.3
django-guardian==1.1.1 django-guardian==1.1.1
pytest-django==2.6
[testenv:py2.6-django1.3] [testenv:py2.6-django1.3]
basepython = python2.6 basepython = python2.6
@ -108,3 +119,4 @@ deps = django==1.3.5
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.3 django-oauth2-provider==0.2.3
django-guardian==1.1.1 django-guardian==1.1.1
pytest-django==2.6