Description
Currently unittest.TestCase instances cannot use fixtures in their test specifications, reportedly due to "different design philosophies".
Would it be possible to create a class decorator to enable this? See this example (runs both with python -m unittest
and pytest
):
import unittest
import pytest
def fixture_wrapper(fn, params):
# XXX discover fixture instead of hardcoding it here
# pytest seems to add extra @py_assert1@ and @py_format1@ stuff here.
#assert params == ('program',)
assert params[0] == 'program'
return lambda self, *args: fn(self, program())
def uses_fixtures(cls):
'''Wraps all unittest.TestCase methods in order to inject fixtures.'''
assert issubclass(cls, unittest.TestCase)
for name in dir(cls):
func = getattr(cls, name)
if not name.startswith('test') or not callable(func):
continue
if func.__code__.co_argcount <= 1:
# ignore methods which do not have fixture dependencies
continue
params = func.__code__.co_varnames[1:]
print(name, params)
setattr(cls, name, fixture_wrapper(func, params))
@pytest.fixture
def program():
return 'dummy'
class TestDemo(object):
def test_1(self, program):
assert program == 'dummy'
@uses_fixtures
class DemoTestCase(unittest.TestCase):
def test_2(self, program):
assert program == 'dummy'
The motivation is to provide a transition path for an existing unittest suite to pytest. Currently I use pytest as test runner for an existing project that otherwise does not depend on pytest. To fix some issues (inability to run part of the tests when some program dependencies are missing) I would like to use fixtures, but without adding a hard dependency on pytest for now. With such a decorator, migration to pytest will require less extensive changes (dropping a decorator vs changing every test function to use the parameter instead of a property that was configured via the unittest setUp method).
Edit: one motivation for using fixtures is the ability to skip tests from it. E.g. if "program" is not available, skip the test.