How do I handle multiple asserts within a single Python unittest? How do I handle multiple asserts within a single Python unittest? python python

How do I handle multiple asserts within a single Python unittest?


With using a subtest, execution would not stop after the first failurehttps://docs.python.org/3/library/unittest.html#subtests

Here is example with two fail asserts:

class TestMultipleAsserts(unittest.TestCase):    def test_multipleasserts(self):        with self.subTest():            self.assertEqual(1, 0)        with self.subTest():            self.assertEqual(2, 0)

Output will be:

======================================================================FAIL: test_multipleasserts (__main__.TestMultipleAsserts) (<subtest>)----------------------------------------------------------------------Traceback (most recent call last):  File "./test.py", line 9, in test_multipleasserts    self.assertEqual(1, 0)AssertionError: 1 != 0======================================================================FAIL: test_multipleasserts (__main__.TestMultipleAsserts) (<subtest>)----------------------------------------------------------------------Traceback (most recent call last):  File "./test.py", line 11, in test_multipleasserts    self.assertEqual(2, 0)AssertionError: 2 != 0----------------------------------------------------------------------Ran 1 test in 0.000sFAILED (failures=2)

You can easy wrap subtest as following

class MyTestCase(unittest.TestCase):    def expectEqual(self, first, second, msg=None):        with self.subTest():            self.assertEqual(first, second, msg)class TestMA(MyTestCase):    def test_ma(self):        self.expectEqual(3, 0)        self.expectEqual(4, 0)


I disagree with the dominant opinion that one should write a test method for each assertion. There are situations where you want to check multiple things in one test method. Here is my answer for how to do it:

# Works with unittest in Python 2.7class ExpectingTestCase(unittest.TestCase):    def run(self, result=None):        self._result = result        self._num_expectations = 0        super(ExpectingTestCase, self).run(result)    def _fail(self, failure):        try:            raise failure        except failure.__class__:            self._result.addFailure(self, sys.exc_info())    def expect_true(self, a, msg):        if not a:            self._fail(self.failureException(msg))        self._num_expectations += 1    def expect_equal(self, a, b, msg=''):        if a != b:            msg = '({}) Expected {} to equal {}. '.format(self._num_expectations, a, b) + msg            self._fail(self.failureException(msg))        self._num_expectations += 1

And here are some situations where I think it's useful and not risky:

1) When you want to test code for different sets of data. Here we have an add() function and I want to test it with a few example inputs. To write 3 test methods for the 3 data sets means repeating yourself which is bad. Especially if the call was more elaborate.:

class MyTest(ExpectingTestCase):    def test_multiple_inputs(self):        for a, b, expect in ([1,1,2], [0,0,0], [2,2,4]):            self.expect_equal(expect, add(a,b), 'inputs: {} {}'.format(a,b))

2) When you want to check multiple outputs of a function. I want to check each output but I don't want a first failure to mask out the other two.

class MyTest(ExpectingTestCase):    def test_things_with_no_side_effects(self):        a, b, c = myfunc()        self.expect_equal('first value', a)        self.expect_equal('second value', b)        self.expect_equal('third value', c)

3) Testing things with heavy setup costs. Tests must run quickly or people stop using them. Some tests require a db or network connection that takes a second which would really slow down your test. If you are testing the db connection itself, then you probably need to take the speed hit. But if you are testing something unrelated, we want to do the slow setup once for a whole set of checks.


This feels like over-engineering to me. Either:

  • Use two asserts in one test case. If the first assert fails, it's true, you won't know whether the second assert passed or not. But you're going to fix the code anyway, so fix it, and then you'll find out if the second assert passed.

  • Write two tests, one to check each condition. If you fear duplicated code in the tests, put the bulk of the code in a helper method that you call from the tests.