Reputation: 879
I am using Python's unittest with simple code like so:
suite = unittest.TestSuite()
suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(module1))
suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(module2))
However, I am wanting to do some custom things to each test after they have been gathered by the suite. I thought I could do something like this to iterate over the test cases in suite:
print suite.countTestCases()
for test in suite: # Also tried with suite.__iter__()
# Do something with test
print test.__class__
However, for as many test cases as I load, it only ever prints
3
<class 'unittest.suite.TestSuite'>
Is there a way I can get all the objects of class TestCase from the suite? Is there some other way I should be loading test cases to facilitate this?
Upvotes: 8
Views: 7140
Reputation: 3192
If you want to get the list of test functions (method prefixed by test
in unittest.TestCase
) in all your test modules:
import unittest
loader = unittest.TestLoader()
suite = loader.discover(YOUR_TEST_PATH)
for test_suite in suite:
for test_case in test_suite:
for test in test_case:
print(f"- {test}")
that gives:
- test_isupper (test_suite1.test_file1.TestA)
- test_upper (test_suite1.test_file1.TestA)
- test_isupper (test_suite2.test_file2.TestB)
- test_upper (test_suite2.test_file2.TestB)
or:
import unittest
loader = unittest.TestLoader()
suite = loader.discover(YOUR_TEST_PATH)
for test_suite in suite:
for test_case in test_suite:
for test in test_case:
print(f"- {test.id()}")
that gives:
test_suite1.test_file1.TestA.test_isupper
test_suite1.test_file1.TestA.test_upper
test_suite2.test_file2.TestB.test_isupper
test_suite2.test_file2.TestB.test_upper
Upvotes: 1
Reputation: 6239
Here is an internal helper function that was recently committed to Django that lets one iterate over a test suite's test cases:
from unittest import TestCase
def iter_test_cases(suite, reverse=False):
"""Return an iterator over a test suite's unittest.TestCase objects."""
if reverse:
suite = reversed(tuple(suite))
for test in suite:
if isinstance(test, TestCase):
yield test
else:
# Otherwise, assume it is a test suite.
yield from iter_test_cases(test, reverse=reverse)
This approach is needed as test suites can be nested arbitrarily deeply.
Upvotes: 1
Reputation: 4358
A neat way of getting list of tests is to use the nose2 collect plugin.
$ nose2 -s <testdir> -v --plugin nose2.plugins.collect --collect-only
test_1 (test_test.TestClass1)
Test Desc 1 ... ok
test_2 (test_test.TestClass1)
Test Desc 2 ... ok
test_3 (test_test.TestClass1)
Test Desc 3 ... ok
test_2_1 (test_test.TestClass2)
Test Desc 2_1 ... ok
test_2_2 (test_test.TestClass2)
Test Desc 2_2 ... ok
----------------------------------------------------------------------
Ran 5 tests in 0.001s
OK
It doesn't really run the tests.
You can install nose2 (and it's plugins) like this:
$ pip install nose2
And of course you can use nose2 to run unit tests e.g. like this or this:
# run tests from testfile.py
$ nose2 -v -s . testfile
# generate junit xml results:
$ nose2 -v --plugin nose2.plugins.junitxml -X testfile --junit-xml
$ mv nose2-junit.xml results_testfile.xml
Upvotes: 1
Reputation: 887
I use this function as some of the elements in suite._tests are suites themselves:
def list_of_tests_gen(s):
""" a generator of tests from a suite
"""
for test in s:
if unittest.suite._isnotsuite(test):
yield test
else:
for t in list_of_tests_gen(test):
yield t
Upvotes: 6