[TIP] dynamically create tests with unittest

Malini Kamalambal malini.kamalambal at RACKSPACE.COM
Thu Feb 26 03:31:14 PST 2015



On 2/25/15 7:08 PM, "Ben Finney" <ben+python at benfinney.id.au> wrote:

>Albert-Jan Roskam <fomcl at yahoo.com> writes:
>
>> With nose one can use generators to dynamically create tests:
>>
>> What is the preferred way to do this with unittest?
>
>I recommend using the ‘testscenarios’ library
><URL:https://pypi.python.org/pypi/testscenarios/>:
>
>    import unittest
>    import testscenarios
>
>    import system_under_test as sut
>
>    class foo_func_TestCase(unittest.TestCase,
>testscenarios.WithScenarios):
>        """ Test cases for the `foo_func` function. """
>
>        scenarios = [
>                ('empty baz', {
>                    'baz': [],
>                    'expected_result': "spam",
>                    }),
>                ('seven baz items', {
>                    'baz': [3, 5, 7, 11, 13, 17, 19],
>                    'expected_result': "beans",
>                    }),
>                ('default no baz', {
>                    'expected_result': "eggs",
>                    }),
>                ]
>
>        def test_returns_expected_result_given_baz(self):
>            """ Should return the expected result given the `baz` value.
>"""
>            baz = getattr(self, 'baz', None)
>            result = sut.foo_func(baz)
>            self.assertEqual(self.expected_result, result)
>
>        def test_quux_remains_unchanged(self):
>            """ Should not affect the `quuz` value. """
>            quux_prev = sut.quux
>            baz = getattr(self, 'baz', None)
>            sut.foo_func(baz)
>            self.assertEqual(quux_prev, sut.quux)
>
>That TestCase class will cause six text cases to be generated during the
>test run: one for each combination of scenario and ‘test_*’ function.
>The TestRunner output for each test case will include both the function
>name and the scenario name, to make it clear which condition caused any
>failure.
>
>Each test case, when created dynamically, will have attributes as
>specified by the name → value mapping for the scenario. Those attributes
>can be used however the test case function chooses.
>
>Adding new scenarios is then a simple matter of adding new entries in
>the scenario collection for the class; all the test case methods will be
>run with all the scenarios, as distinct test cases in the run.
>
>-- 
> \            “Without cultural sanction, most or all of our religious |
>  `\          beliefs and rituals would fall into the domain of mental |
>_o__)                                 disturbance.” ―John F. Schumaker |
>Ben Finney


ddt is another good option.
See docs here http://ddt.readthedocs.org/en/latest/
Rewriting Ben's example with ddt would looks something like below.


import unittest
import ddt

    import system_under_test as sut

@ddt.ddt
    class foo_func_TestCase(unittest.TestCase):
        """ Test cases for the `foo_func` function. """


@ddt.data([], [3, 5, 7, 11, 13, 17, 19])
        def test_returns_expected_result_given_baz(self, baz):
            """ Should return the expected result given the `baz` value.
"""
result = sut.foo_func(baz)
            self.assertEqual(self.expected_result, result)

        def test_quux_remains_unchanged(self):
            """ Should not affect the `quuz` value. """
            quux_prev = sut.quux
            baz = getattr(self, 'baz', None)
            sut.foo_func(baz)
            self.assertEqual(quux_prev, sut.quux)




Regards,
Malini




More information about the testing-in-python mailing list