elynnaie
elynnaie

Reputation: 879

How can I extract a list of TestCases from a TestSuite?

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

Answers (5)

OlivierM
OlivierM

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

cjerdonek
cjerdonek

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

gaoithe
gaoithe

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

Totoro
Totoro

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

dorsh
dorsh

Reputation: 24670

Try

  for test in suite:
    print test._tests

Upvotes: 5

Related Questions