It seems that people in the go area prefer to write unit tests in a format called table driven test (although other languages do the same). I didn't invent it because it existed or existed).
I thought about what to do if I wrote a table driven test in python.
For example, suppose you want to test a function called add like this:
def add(x, y):
return x + y
If you write it honestly within the range of the unittest module of python, it looks like the following.
import unittest
class Tests(unittest.TestCase):
def _callFUT(self, x, y):
from add import add
return add(x, y)
def test_with_positive(self):
actual = self._callFUT(10, 10)
self.assertEqual(actual, 20)
def test_with_zero(self):
actual = self._callFUT(10, 0)
self.assertEqual(actual, 10)
def test_with_negative(self):
actual = self._callFUT(10, -10)
self.assertEqual(actual, 0)
def test_with_biiiiiiiiiig(self):
actual = self._callFUT(
10,
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
)
self.assertEqual(
actual,
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010,
)
long. I'm tired.
(CallFUT is religious. See this area for details)
table driven test
The table driven test gives a crisp feeling. It seems good to use subTest.
import unittest
from collections import namedtuple
class Tests(unittest.TestCase):
def _callFUT(self, x, y):
from add import add
return add(x, y)
def test_it(self):
C = namedtuple("C", "msg x y expected")
candidates = [
C(msg="with positive", x=10, y=10, expected=20),
C(msg="with zero", x=10, y=0, expected=10),
C(msg="with negative", x=10, y=-10, expected=0),
C(
msg="with biiiiiiig",
x=10,
y=10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
expected=10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010,
),
]
for c in candidates:
with self.subTest(msg=c.msg):
actual = self._callFUT(c.x, c.y)
self.assertEqual(actual, c.expected)
Below are my personal preferences
--Using namedtuple --Write msg together --_callFUT (If the test method ends with one, it may not be necessary to separate it)
If successful, it will be counted as one.
.
----------------------------------------------------------------------
Ran 1 test in 0.002s
OK
If it fails, it will be counted as N, which is good.
======================================================================
FAIL: test_it (__main__.Tests) [with positive]
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests.py", line 26, in test_it
self.assertEqual(actual, c.expected + 1)
AssertionError: 20 != 21
======================================================================
FAIL: test_it (__main__.Tests) [with zero]
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests.py", line 26, in test_it
self.assertEqual(actual, c.expected + 1)
AssertionError: 10 != 11
======================================================================
FAIL: test_it (__main__.Tests) [with negative]
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests.py", line 26, in test_it
self.assertEqual(actual, c.expected + 1)
AssertionError: 0 != 1
======================================================================
FAIL: test_it (__main__.Tests) [with biiiiiiig]
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests.py", line 26, in test_it
self.assertEqual(actual, c.expected + 1)
AssertionError: 10000[33 chars]000000000000000000000000000000000000000000000000000000000000010 != 10000[33 chars]000000000000000000000000000000000000000000000000000000000000011
----------------------------------------------------------------------
Ran 1 test in 0.003s
FAILED (failures=4)
Can anyone write about a table driven test using pytest?
Recommended Posts