Skip to content

Instantly share code, notes, and snippets.

@simonw
Created March 27, 2016 23:00
Show Gist options
  • Select an option

  • Save simonw/6aaab51f84f163f3a675 to your computer and use it in GitHub Desktop.

Select an option

Save simonw/6aaab51f84f163f3a675 to your computer and use it in GitHub Desktop.
Parameterized unit tests for Python - syntactic sugar inspired by https://chris-lamb.co.uk/posts/generating-dynamic-python-tests-using-metaclasses
class ParameterizedTestsMeta(type):
def __new__(cls, name, bases, attrs):
skip_these_names = []
i = 1
for name, fn in attrs.items():
if name.startswith('test_') and callable(fn) and getattr(fn, '_parameterized_params', None):
skip_these_names.append(name)
for params in fn._parameterized_params:
attrs['%s_%d' % (name, i)] = cls.make_parameterized_test(fn, params)
i += 1
new_attrs = dict([
pair for pair in attrs.items() if pair[0] not in skip_these_names
])
return super(ParameterizedTestsMeta, cls).__new__(cls, name, bases, new_attrs)
@classmethod
def make_parameterized_test(cls, fn, params):
def test_fn(self):
fn(self, params)
return test_fn
def parameterized(*params):
def decorator(fn):
fn._parameterized_params=params
return fn
return decorator
import unittest
from parameterized import ParameterizedTestsMeta, parameterized
class DoubleTests(unittest.TestCase):
__metaclass__ = ParameterizedTestsMeta
@parameterized(
(5, 10),
(6, 12),
(20, 40),
)
def test_double(self, (input, expected)):
self.assertEqual(expected, double(input))
# The function we are testing
def double(i):
return i * 2
if __name__ == '__main__':
unittest.main()
@simonw

simonw commented Mar 27, 2016

Copy link
Copy Markdown
Author

Here's example output if we add another pair to the parameterized list of (30, 31):

$ python param.py
...F
======================================================================
FAIL: test_double_4 (__main__.test_double)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "param.py", line 21, in test_fn
    fn(self, params)
  File "param.py", line 40, in test_double
    self.assertEqual(expected, double(input))
AssertionError: 31 != 60

----------------------------------------------------------------------
Ran 4 tests in 0.000s

FAILED (failures=1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment