A more data-oriented approach might be clearer than the one used in Andrew Dalke's answer:
"""Parametrized unit test.
Builds a single TestCase class which tests if its
`somevalue` method is equal to the numbers 1 through 4.
This is accomplished by
creating a list (`cases`)
of dictionaries which contain test specifications
and then feeding the list to a function which creates a test case class.
When run, the output shows that three of the four cases fail,
as expected:
>>> import sys
>>> from unittest import TextTestRunner
>>> run_tests(TextTestRunner(stream=sys.stdout, verbosity=9))
... # doctest: +ELLIPSIS
Test if self.somevalue equals 4 ... FAIL
Test if self.somevalue equals 1 ... FAIL
Test if self.somevalue equals 3 ... FAIL
Test if self.somevalue equals 2 ... ok
======================================================================
FAIL: Test if self.somevalue equals 4
----------------------------------------------------------------------
Traceback (most recent call last):
...
AssertionError: 2 != 4
======================================================================
FAIL: Test if self.somevalue equals 1
----------------------------------------------------------------------
Traceback (most recent call last):
...
AssertionError: 2 != 1
======================================================================
FAIL: Test if self.somevalue equals 3
----------------------------------------------------------------------
Traceback (most recent call last):
...
AssertionError: 2 != 3
----------------------------------------------------------------------
Ran 4 tests in ...s
FAILED (failures=3)
"""
from unittest import TestCase, TestSuite, defaultTestLoader
cases = [{'name': "somevalue_equals_one",
'doc': "Test if self.somevalue equals 1",
'value': 1},
{'name': "somevalue_equals_two",
'doc': "Test if self.somevalue equals 2",
'value': 2},
{'name': "somevalue_equals_three",
'doc': "Test if self.somevalue equals 3",
'value': 3},
{'name': "somevalue_equals_four",
'doc': "Test if self.somevalue equals 4",
'value': 4}]
class BaseTestCase(TestCase):
def setUp(self):
self.somevalue = 2
def test_n(self, n):
self.assertEqual(self.somevalue, n)
def make_parametrized_testcase(class_name, base_classes, test_method, cases):
def make_parametrized_test_method(name, value, doc=None):
def method(self):
return test_method(self, value)
method.__name__ = "test_" + name
method.__doc__ = doc
return (method.__name__, method)
test_methods = (make_parametrized_test_method(**case) for case in cases)
class_dict = dict(test_methods)
return type(class_name, base_classes, class_dict)
TestCase = make_parametrized_testcase('TestOneThroughFour',
(BaseTestCase,),
test_n,
cases)
def make_test_suite():
load = defaultTestLoader.loadTestsFromTestCase
return TestSuite(load(TestCase))
def run_tests(runner):
runner.run(make_test_suite())
if __name__ == '__main__':
from unittest import TextTestRunner
run_tests(TextTestRunner(verbosity=9))
I'm not sure what voodoo is involved in determining the order in which the tests are run, but the doctest passes consistently for me, at least.
For more complex situations it's possible to replace the values element of the cases dictionaries with a tuple containing a list of arguments and a dict of keyword arguments. Though at that point you're basically coding lisp in python.