python - Passing arguments (for argparse) with unittest discover -
foo python project deep directory nesting, including ~30 unittest files in various subdirectories. within foo's setup.py, i've added custom "test" command internally running
python -m unittest discover foo '*test.py' note uses unittest's discovery mode.
since of tests extremely slow, i've decided tests should have "levels". answer this question explained how unittest , argparse work each other. now, can run individual unittest file, foo/bar/_bar_test.py, with
python foo/bar/_bar_test.py --level=3 and level-3 tests run.
the problem can't figure out how pass custom flag (in case "--level=3" using discover. try fails, e.g.:
$ python -m unittest discover --level=3 foo '*test.py' usage: python -m unittest discover [options] python -m unittest discover: error: no such option: --level $ python -m --level=3 unittest discover foo '*test.py' /usr/bin/python: no module named --level=3 how can pass --level=3 individual unittests? if possible, i'd avoid dividing different-level tests different files.
bounty edit
the pre-bounty (fine) solution suggests using system environment variables. not bad, i'm looking cleaner.
changing multiple-file test runner (i.e., python -m unittest discover foo '*test.py') else fine, long as:
- it allows generating single report multiple-file unittests.
- it can somehow support multiple test levels (either using technique in question, or using other different mechanism).
this doesn't pass args using unittest discover, accomplishes trying do.
this leveltest.py. put somewhere in module search path (maybe current directory or site-packages):
import argparse import sys import unittest # part copied unittest.__main__.py if sys.argv[0].endswith("__main__.py"): import os.path # change sys.argv[0] make message more useful # use executable without path, unquoted # (it's hint anyway) # (if have spaces in executable deserve!) executable = os.path.basename(sys.executable) sys.argv[0] = executable + " -m leveltest" del os def _id(obj): return obj # decorator assigns test levels test cases (classes , methods) def level(testlevel): if unittest.level < testlevel: return unittest.skip("test level low.") return _id def parse_args(): parser = argparse.argumentparser() parser.add_argument('--level', type=int, default=3) ns, args = parser.parse_known_args(namespace=unittest) return ns, sys.argv[:1] + args if __name__ == "__main__": ns, remaining_args = parse_args() # invokes unittest when leveltest invoked -m flag like: # python -m leveltest --level=2 discover --verbose unittest.main(module=none, argv=remaining_args) here how use in example testproject.py file:
import unittest import leveltest # needed before uses of @leveltest.level() decorator # parse "--level" command argument , set test level when # test file run directly -m if __name__ == "__main__": ns, remaining_args = leveltest.parse_args() @leveltest.level(2) class teststringmethods(unittest.testcase): @leveltest.level(5) def test_upper(self): self.assertequal('foo'.upper(), 'foo') @leveltest.level(3) def test_isupper(self): self.asserttrue('foo'.isupper()) self.assertfalse('foo'.isupper()) @leveltest.level(4) def test_split(self): s = 'hello world' self.assertequal(s.split(), ['hello', 'world']) # check s.split fails when separator not string self.assertraises(typeerror): s.split(2) if __name__ == '__main__': # invokes unittest when file executed -m unittest.main(argv=remaining_args) you can run tests running testproject.py directly, like:
~roottwo\projects> python testproject.py --level 2 -v test_isupper (__main__.teststringmethods) ... skipped 'test level low.' test_split (__main__.teststringmethods) ... skipped 'test level low.' test_upper (__main__.teststringmethods) ... skipped 'test level low.' ---------------------------------------------------------------------- ran 3 tests in 0.000s ok (skipped=3) ~roottwo\projects> python testproject.py --level 3 -v test_isupper (__main__.teststringmethods) ... ok test_split (__main__.teststringmethods) ... skipped 'test level low.' test_upper (__main__.teststringmethods) ... skipped 'test level low.' ---------------------------------------------------------------------- ran 3 tests in 0.001s ok (skipped=2) ~roottwo\projects> python testproject.py --level 4 -v test_isupper (__main__.teststringmethods) ... ok test_split (__main__.teststringmethods) ... ok test_upper (__main__.teststringmethods) ... skipped 'test level low.' ---------------------------------------------------------------------- ran 3 tests in 0.001s ok (skipped=1) ~roottwo\projects> python testproject.py --level 5 -v test_isupper (__main__.teststringmethods) ... ok test_split (__main__.teststringmethods) ... ok test_upper (__main__.teststringmethods) ... ok ---------------------------------------------------------------------- ran 3 tests in 0.001s ok by using unittest discovery this:
~roottwo\projects> python -m leveltest --level 2 -v test_isupper (testproject.teststringmethods) ... skipped 'test level low.' test_split (testproject.teststringmethods) ... skipped 'test level low.' test_upper (testproject.teststringmethods) ... skipped 'test level low.' ---------------------------------------------------------------------- ran 3 tests in 0.003s ok (skipped=3) ~roottwo\projects> python -m leveltest --level 3 discover -v test_isupper (testproject.teststringmethods) ... ok test_split (testproject.teststringmethods) ... skipped 'test level low.' test_upper (testproject.teststringmethods) ... skipped 'test level low.' ---------------------------------------------------------------------- ran 3 tests in 0.001s ok (skipped=2) ~roottwo\projects> python -m leveltest --level 4 -v test_isupper (testproject.teststringmethods) ... ok test_split (testproject.teststringmethods) ... ok test_upper (testproject.teststringmethods) ... skipped 'test level low.' ---------------------------------------------------------------------- ran 3 tests in 0.001s ok (skipped=1) ~roottwo\projects> python -m leveltest discover --level 5 -v test_isupper (testproject.teststringmethods) ... ok test_split (testproject.teststringmethods) ... ok test_upper (testproject.teststringmethods) ... ok ---------------------------------------------------------------------- ran 3 tests in 0.001s ok or specifying test cases run, like:
~roottwo\projects>python -m leveltest --level 3 testproject -v test_isupper (testproject.teststringmethods) ... ok test_split (testproject.teststringmethods) ... skipped 'test level low.' test_upper (testproject.teststringmethods) ... skipped 'test level low.' ---------------------------------------------------------------------- ran 3 tests in 0.002s ok (skipped=2)
Comments
Post a Comment