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