Search code examples
pythonpython-3.xpytestpython-unittest

How do I convert a unittest subtest to pytest


Does pytest (2.8.3) have an equivalent of self.subTest() (as found in Python 3's unittest)?

Here's a simplified version of the code I'm trying to convert:

class MyUnittestTest(TestCase):
    def test_permutations(self):
        on_off = True, False
        for prefix, params, suffix in product(on_off, on_off, on_off):

            expected_prefix = 'something' if prefix else ''
            expected_params = ('something',) if params else ()
            expected_suffix = b'something' if suffix else b''

            with self.subTest(prefix=prefix, params=params, suffix=suffix):
                result = do_magic(prefix=prefix, params=params, suffix=suffix)

                self.assertEqual(result.prefix, expected_prefix)
                self.assertEqual(result.params, expected_params)
                self.assertEqual(result.suffix, expected_suffix)

At the moment, all I have is defining one test per permutation. There must be a better way than this:

class MyPytestTest:
    def test_on_on_on(self):
        expected_prefix = ...

        result = do_magic(...)

        assert ...

    def test_on_on_off(self):
        ...

Solution

  • Pytest does not have this functionality natively, but it can be added with the pytest-subtests plugin.

    To use it, inject the subtests fixture into the test:

    def test_permutations(subtests):
        on_off = True, False
        for prefix, params, suffix in product(on_off, on_off, on_off):
            with subtests.test(prefix=prefix, params=params, suffix=suffix):
                result = do_magic(prefix=prefix, params=params, suffix=suffix)
                assert ...
    

    In many cases pytest.mark.parametrize is a better alternative, though it does not work in the same way. In particular, shared test setup/teardown is quite different.