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.
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?