Greg Wilson
Greg Wilson

Reputation: 1363

What is the simplest way to make manage.py test app.TestCase work again after replacing tests.py with tests/ directory?

I have replaced project/app/tests.py with a project/app/tests/ directory. The directory contains several Python files (call them apples.py, bananas.py, etc.), each of which defines one or more classes derived from TestCase (call them TestApples, TestBananas, etc.). The file project/app/tests/__init__.py contains

from apples import TestApples
from bananas import TestBananas

The command manage.py test app still works, but manage.py test app.bananas and manage.py test app.tests.bananas do not, e.g.:

ValueError: Test label 'app.bananas' does not refer to a test

manage.py test app.tests.bananas fails with the same error, but manage.py test app.tests.bananas.TestBananas is more hopeful:

ValueError: Test label 'store.tests.bananas.TestBananas' should be of the form app.TestCase or app.TestCase.test_method

The Django docs and Python docs suggest that the solution is to write a custom test runner or test collector and plug it in; this StackOverflow question goes down the same route, then seems to recommend switching to django-nose. I'd rather not unless I have to, and I'm curious to see how to make this work with Django's standard tools. Anyone have a simple(ish) solution?

Upvotes: 3

Views: 2759

Answers (4)

Tarsis Azevedo
Tarsis Azevedo

Reputation: 1523

I just do this tutorial.

Edit: after django 1.6, the test discovery mechanism changed. You just have to create a folder tests with an __init__.py file inside, and put your test files there. Your test files should match test*.py pattern.

Upvotes: 2

Bryce Drennan
Bryce Drennan

Reputation: 709

In your example, if you run manage.py test app.TestBananas then you can run that specific test.

You can get everything working by making sure all your tests are imported into __init__.py but when you have lots of tests this becomes difficult to manage. If you want to run the tests in PyCharm then django-nose isn't an option.

To make this easier we can have the test suite automatically find all tests in the tests package. Just put this in __init__.py (Be sure to replace "appname"):

def suite():   
    return unittest.TestLoader().discover("appname.tests", pattern="*.py")

This still won't allow us to run specific tests. To do that you'll need to add this code at the top of __init__.py:

import pkgutil
import unittest

for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
    module = loader.find_module(module_name).load_module(module_name)
    for name in dir(module):
        obj = getattr(module, name)
        if isinstance(obj, type) and issubclass(obj, unittest.case.TestCase):
            exec ('%s = obj' % obj.__name__)

Now you can run all your tests via manage.py test app or specific ones via manage.py test app.TestApples

Upvotes: 2

diogobaeder
diogobaeder

Reputation: 481

Did you try renaming your test files to "test_foo.py", instead of "foo.py", for example?

Upvotes: 0

jbalogh
jbalogh

Reputation: 11

I use django-nose! Don't be scared of packages.

Upvotes: 0

Related Questions