[Fixed]-Run specific Django tests (with django-nose?)

6👍

The problem you ran into is that Nose determines whether or not to include a method into the set of tests to run by looking at the name recorded on the function itself, rather than the attribute that gives access to the function. If I rename your passer and failer to test_pass and test_fail then Nose is able to find the tests. So the functions themselves have to be named in a way that will be matched by what is given to -m (or its default value).

Here’s the modified code that gives the expected results:

from django.test import TestCase
from sys import modules

current_module = modules[__name__]

def test_pass(self, *args, **kw):
    self.assertEqual(1, 1)

def test_fail(self, *args, **kw):
    self.assertEqual(1, 2)

# Create a hundred ...
for i in xrange(100):
    # ... of a stupid TestCase class that has 1 method that passes if `i` is
    # even and fails if `i` is odd
    klass_name = "Test_%s" % i
    if i % 2:  # Test passes if even
        klass_attrs = {
            'test_something_%s' % i: test_pass
        }
    else:      # Fail if odd
        klass_attrs = {
            'test_something_%s' % i: test_fail
        }
    klass = type(klass_name, (TestCase,), klass_attrs)

    # Set the class as "child" of the current module so that django test runner
    # finds it
    setattr(current_module, klass_name, klass)

# This prevents Nose from seeing them as tests after the loop is over.
test_pass = None
test_fail = None

Without the final two assignments to None, Nose will consider the two top level functions to be module-level tests and will run them in addition to the tests in the classes.

Another way to get the same results would be to define __test__ on your two functions:

def passer(self, *args, **kw):
    self.assertEqual(1, 1)
passer.__test__ = 1

def failer(self, *args, **kw):
    self.assertEqual(1, 2)
failer.__test__ = 1

And at the end of the file:

# This prevents Nose from seeing them as tests after the loop is over.
passer = None
failer = None

Nose looks for the presence of these on functions and if present and set to a value is considered to be true, it will take the function as a test case.

The logic governing the selection of methods can be found in Nose’s selector.py file, at the wantMethod method:

def wantMethod(self, method):
        """Is the method a test method?
        """
        try:
            method_name = method.__name__
        except AttributeError:
            # not a method
            return False
        if method_name.startswith('_'):
            # never collect 'private' methods
            return False
        declared = getattr(method, '__test__', None)
        if declared is not None:
            wanted = declared
        else:
            wanted = self.matches(method_name)
        plug_wants = self.plugins.wantMethod(method)
        if plug_wants is not None:
            wanted = plug_wants
        log.debug("wantMethod %s? %s", method, wanted)
        return wanted

I’m not seeing a clear way to use -m to run only some tests the way you want it. The problem is that -m matches file, directorie, module, class, and function names equally. If you set something like -m0$ then all the individual parts I just listed must match the regular expression for the test to be selected. (Nose does not combine them and then match on the combination.) It is possible to list tests individually on the command line but this is a poor substitute to a regular expression match.

👤Louis

3👍

In general you can run your specific test with something like this:

# assuming your tests are in core/tests.py
python manage.py test core.tests:CoreTestCase.my_specific_test

Have you tried this approach?

Leave a comment