A note on parameterized testing
If your test is in the business of calculating the expected output from the inputs, then your test is duplicating the logic from the code under test.
And there is a reason why too much logic in tests is frowned upon: If you implement the same logic twice, you are prone to repeat the same mistakes in the test which you already made in the real implementation.
for c in [
Case(socket_type=SOCK_STREAM, fruit="Apple"),
Case(socket_type=SOCK_STREAM, fruit="Orange"),
Case(socket_type=SOCK_DGRAM, fruit="Apple"),
Case(socket_type=SOCK_DGRAM, fruit="Orange"),
]:
# Oh no, surprise logic in the test!
# This becomes hard to find when the test gets longer.
expected = 1
if c.socket_type == SOCK_STREAM and c.fruit == "Orange":
expected = 0 # Expecting nothing in this case
self.assertEqual(expected, operation(c.socket_type, c.fruit))
Better is to flatten out the expected results into the test table and remove that logic from the test:
for c in [
Case(socket_type=SOCK_STREAM, fruit="Apple", expected=1),
Case(socket_type=SOCK_STREAM, fruit="Orange", expected=0), # special case
Case(socket_type=SOCK_DGRAM, fruit="Apple", expected=1),
Case(socket_type=SOCK_DGRAM, fruit="Orange", expected=1),
]:
self.assertEqual(c.expected, operation(c.socket_type, c.fruit))
This is one of these articles that I’m writing just so that I can point to it later.