Reputation: 1150
I have several test modules that are all invoked together via a driver script that can take a variety of arguments. The tests themselves are written using the python unittest module.
import optparse
import unittest
import sys
import os
from tests import testvalidator
from tests import testmodifier
from tests import testimporter
#modify the path so that the test modules under /tests have access to the project root
sys.path.insert(0, os.path.dirname(__file__))
def run(verbosity):
if verbosity == "0":
sys.stdout = open(os.devnull, 'w')
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.TestLoader().loadTestsFromTestCase(testvalidator.TestValidator))
test_suite.addTest(unittest.TestLoader().loadTestsFromTestCase(testmodifier.TestModifier))
test_suite.addTest(unittest.TestLoader().loadTestsFromTestCase(testimporter.TestDataImporter))
unittest.TextTestRunner(verbosity=int(verbosity)).run(test_suite)
if __name__ == "__main__":
#a simple way to control output verbosity
parser = optparse.OptionParser()
parser.add_option("--verbosity", "--verbosity", dest="verbosity", default="0")
(options, args) = parser.parse_args()
run(options.verbosity)
My issue is that, within these test modules, I have certain tests I'd like to skip based on different parameters passed to the driver. I'm aware that unittest provides a family of decorators meant to do this, but I don't know the best way to pass this information on to the individual modules. If I had a --skip-slow
argument, for example, how could I then annotate tests as slow, and have them skipped?
Thank you for your time.
Upvotes: 6
Views: 1808
Reputation: 11415
Here's how I solved this problem. At the bottom of my module, I put this code to set a global variable based on the presence of a --slow
argument in argv
:
if __name__ == "__main__":
try:
i = sys.argv.index("--slow")
run_slow_tests=True
del sys.argv[i]
except ValueError:
pass
unittest.main()
Then at the beginning of test functions which would be slow to run, I put this statement. It raises the unittest.SkipTest() exception if the flag isn't set to include slow tests.
if not run_slow_tests:
raise unittest.SkipTest('Slow test skipped, unless --slow given in sys.argv.')
Then when I invoke the module normally, the slow tests are skipped.
% python src/my_test.py -v
test_slow (__main__.Tests) ... skipped 'Slow test skipped, unless --slow given in sys.argv.'
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK (skipped=1)
And when I add the --slow
, the slow tests in that module run:
% python src/my_test.py -v --slow
test_slow (__main__.Tests) ... ok
----------------------------------------------------------------------
Ran 1 test in 10.110s
OK
Unfortunately, this doesn't work with Unittest's test discovery.
% python -m unittest discover src "*_test.py" --slow
usage: python -m unittest discover [-h] [-v] [-q] [--locals] [-f] [-c] [-b]
[-k TESTNAMEPATTERNS] [-s START]
[-p PATTERN] [-t TOP]
python -m unittest discover: error: unrecognized arguments: --slow
It also didn't work to use the @unittest.SkipUnless() decorator. I suspect this is because the decorator evaluates its arguments at module definition time, but the argument isn't set to the correct value until module run time, which is later.
It isn't perfect, but it lets me work within the Python standard library. A requirement like this is a good reason to adopt a better framework, such as nose tests. For my current project, I prefer to avoid installing any outside modules.
Upvotes: 0
Reputation: 3506
I had in fact been wondering this myself, and finally found the solution.
main file...
...
if __name__ == '__main__':
args = argparser()
from tests import *
...
And in your test modules, just do:
from __main__ import args
print args
I tested this out, and it worked rather nicely. Nice thing is how simple it is, and it's not too much of a hack at all.
Upvotes: 2
Reputation: 40414
You can use nose test runner with the attrib plugin that lets you select test cases based on attributes. In particular, the example in the plugin documentation uses @attr(slow)
to mark slow test cases.
After that, from the command line:
To select all the test cases marked as slow
:
$ nosetests -a slow
To select all the test cases not marked as slow
:
$ nosetests -a '!slow'
Upvotes: 2