Unit test Theories in Python?

In a previous life, I worked a bit on Java development and found JUnit Theories quite useful. Is there a similar mechanism for Python?

I am currently doing something like:

def some_test(self): cases = [('some sample input', 'some expected value'), ('some other input', 'some other expected value')] for value, expected in cases: result = method_under_test(value) self.assertEqual(expected, result) 

But this is rather awkward, if the first “case” fails, all the others cannot be started.

+5
source share
3 answers

It looks like pytest can do something like this: http://pytest.org/latest/parametrize.html#parametrize-basics

I have not tried myself.

+2
source

I do not know any built-in functions for this in any general testing framework. The only problem with your solution is that the iteration is inside the test. Rather, it should be outside and generate tests, maybe something like this

 import unittest def _apply(func, args): """Return a function with args applied after first argument""" def wrapped(self): return func(self, *args) return wrapped class TheoryMeta(type): """Metaclass that replaces test methods with multiple methods for each test case""" def __new__(meta, name, bases, attrs): newattrs = {} cases = attrs.pop('cases', []) for name, value in attrs.items(): if not name.startswith('test') or not callable(value): newattrs[name] = value continue for n, args in enumerate(cases): test_name = '%s_%d' % (name, n) newattrs[test_name] = _apply(value, args) return super().__new__(meta, name, bases, newattrs) class TestCase(unittest.TestCase, metaclass=TheoryMeta): pass 

Then, to use it, create a subclass of TestCase that has the cases attribute, which is a list of arguments that apply to each test method in the test case.

 class TestAdd(TestCase): cases = [ # (a, b) (1, 1), (2, 0), (3, 0), ] def test_add(self, a, b): self.assertEqual(a + b, 2) ====================================================================== FAIL: test_add_2 (__main__.__qualname__) ---------------------------------------------------------------------- Traceback (most recent call last): File "test.py", line 7, in wrapped return func(self, *args) File "test.py", line 41, in test_add self.assertEqual(a + b, 2) AssertionError: 3 != 2 ---------------------------------------------------------------------- Ran 3 tests in 0.001s 

Depending on your needs and test setup, you can better use only those test methods developed with monkey patches in TestCase, instead of using a metaclass. Or you can generate them by overriding loadTestsFrom ... in TestLoader . In any case, use sample data to generate test methods.

0
source

As it turned out, there is something like this built-in with Python 3.4 - subTest : https://docs.python.org/3.4/library/unittest.html#distinguishing-test-iterations-using-subtests

Not as elegant as py.test parameterized tests, or jUnit Theories, but if you want to use standard-lib and use the relatively recent version of Python, this is an option.

0
source

All Articles