'Insufficient output from unittest subTest elements under pytest

I'm interested in using unittest's subTest for looping through some very similar tests. I found that, when I run tests written in this way under pytest (or nosetests), the output does not contain information about the individual failures. Taking the example from the docs:

import unittest

class NumbersTest(unittest.TestCase):
    def test_even(self):
        """
        Test that numbers between 0 and 5 are all even.
        """
        for i in range(0, 6):
            with self.subTest(i=i):
                self.assertEqual(i % 2, 0)

if __name__ == '__main__':
    unittest.main()

If I run python test_even.py, it clearly shows three failures, as expected:

======================================================================
FAIL: test_even (__main__.NumbersTest) (i=1)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_even.py", line 10, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

======================================================================
FAIL: test_even (__main__.NumbersTest) (i=3)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_even.py", line 10, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

======================================================================
FAIL: test_even (__main__.NumbersTest) (i=5)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_even.py", line 10, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

----------------------------------------------------------------------
Ran 1 test in 0.002s

FAILED (failures=3)

However, if I run pytest -v test_even.py, it only tells me there was a failure in this test. I can't see which elements failed:

test_even.py::NumbersTest::test_even FAILED                                                                      [100%]

======================================================= FAILURES =======================================================
________________________________________________ NumbersTest.test_even _________________________________________________

self = <test_even.NumbersTest testMethod=test_even>

    def test_even(self):
        """
        Test that numbers between 0 and 5 are all even.
        """
        for i in range(0, 6):
            with self.subTest(i=i):
>               self.assertEqual(i % 2, 0)
E               AssertionError: 1 != 0

test_even.py:10: AssertionError
=============================================== 1 failed in 0.15 seconds ===============================================

Is there a way to show up the individual failures? Ideally, I'd also like some sort of output for the ones that passed, just to reassure myself that the test discovery is working properly!



Solution 1:[1]

It seems that pytest does not yet support subTest. One solution might be to ditch unittest altogether and write native pytest tests:

import pytest

@pytest.mark.parametrize("test_input", range(0, 6))
def test_even(test_input):
    assert test_input % 2 == 0

if __name__ == '__main__':
    pytest.main([__file__])

Solution 2:[2]

Once pytest-subtests is added to the environment, this just works with the script from the original question:

$ pytest test_even.py
============================= test session starts ==============================
platform linux -- Python 3.10.4, pytest-7.1.2, pluggy-1.0.0
rootdir: /net/home/h04/hadru/python
plugins: subtests-0.7.0
collected 1 item                                                               

test_even.py .                                                        [100%]

=================================== FAILURES ===================================
_________________________ NumbersTest.test_even (i=1) __________________________

self = <test_even.NumbersTest testMethod=test_even>

    def test_even(self):
        """
        Test that numbers between 0 and 5 are all even.
        """
        for i in range(0, 6):
            with self.subTest(i=i):
>               self.assertEqual(i % 2, 0)
E               AssertionError: 1 != 0

test_even.py:10: AssertionError
_________________________ NumbersTest.test_even (i=3) __________________________

self = <test_even.NumbersTest testMethod=test_even>

    def test_even(self):
        """
        Test that numbers between 0 and 5 are all even.
        """
        for i in range(0, 6):
            with self.subTest(i=i):
>               self.assertEqual(i % 2, 0)
E               AssertionError: 1 != 0

test_even.py:10: AssertionError
_________________________ NumbersTest.test_even (i=5) __________________________

self = <test_even.NumbersTest testMethod=test_even>

    def test_even(self):
        """
        Test that numbers between 0 and 5 are all even.
        """
        for i in range(0, 6):
            with self.subTest(i=i):
>               self.assertEqual(i % 2, 0)
E               AssertionError: 1 != 0

test_even.py:10: AssertionError
=========================== short test summary info ============================
SUBFAIL test_even.py::NumbersTest::test_even - AssertionError: 1 != 0
SUBFAIL test_even.py::NumbersTest::test_even - AssertionError: 1 != 0
SUBFAIL test_even.py::NumbersTest::test_even - AssertionError: 1 != 0
========================= 3 failed, 1 passed in 0.10s ==========================

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 RuthC
Solution 2 RuthC