3

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?

Community
  • 1
  • 1
Greg Wilson
  • 1,015
  • 10
  • 24
  • I recently asked a very similar question. I was directed to django-nose and I happily made the switch. Work required was close to none, as no change is required to the tests themselves. Do you have specific reasons not to make the switch? – tawmas Jul 13 '11 at 20:30

4 Answers4

2

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

Bryce Drennan
  • 699
  • 6
  • 9
2

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.

Tarsis Azevedo
  • 1,463
  • 14
  • 21
0

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

jbalogh
  • 11
  • 2
  • nose has been in maintenance mode since at least 2015. django-nose is in maintenance mode as well, and the sole maintainer is no longer an active user. See Jazzband.co to learn how django-nose is maintained and how you can help. New projects should consider using pytest, or unittest with the Django testing framework. Source: https://github.com/jazzband/django-nose#note-to-users – guettli Oct 01 '21 at 06:42
0

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

diogobaeder
  • 461
  • 5
  • 16