given a Python class hierarchy, say
class Base:
def method1
def method2
def method3
...
class Derived1(Base)
class Derived2(Base)
etc.
and given that Base defines some common interface which is re-implemented differently in each Derived class. What would be the most straightforward way to unit test all member functions of all classes. Since i'm having a class hierarchy, i thought of doing something like...
class MyTestCase(unittest.TestCase):
def testMethod1:
## Just as an example. Can be similar
self.failUnless(self.instance.method1())
def testMethod2
...
And then setting up the test suite with test cases for different instantiations of the class hierarchy But how do i get the "instance" parameter into the MyTestCase class?
The skip
decorator applies to all of the subclasses as well as the base class so you cannot simply tell unittest to skip the base. The simplest thing is probably to not have the base test class derive from TestCase at all:
import unittest
class Base: pass
class Derived1(Base): pass
class BaseTest(object):
cls = None
def setUp(self):
self.instance = self.cls()
def test_Method1(self):
print("run test_Method1, cls={}".format(self.cls))
class TestParent(BaseTest, unittest.TestCase):
cls = Base
class TestDerived1(BaseTest, unittest.TestCase):
cls = Derived1
unittest.main()
The equivalent code using pytest would be:
class Base: pass
class Derived1(Base): pass
class BaseTest(object):
cls = None
def __init__(self):
self.instance = self.cls()
def test_Method1(self):
print("run test_Method1, cls={}".format(self.cls))
class TestParent(BaseTest):
cls = Base
class TestDerived1(BaseTest):
cls = Derived1
pytest by default looks in files with a test_
prefix for functions with a test_
prefix or classes with a Test
prefix. In the test classes it looks for methods with the test_
prefix.
So it should all just work as desired if converted to use pytest.
Alternatively with pytest you could parametrize test functions with the classes to be tested but that's probably a bigger change. Code like this would run the test once for each class listed in the instance fixture params:
import pytest
@pytest.fixture(params=[Base, Derived1])
def instance(request: FixtureRequest) -> Base:
cls: Base = request.param
yield cls()
def test_something(instance: Base) -> None:
assert instance.method() == 42 # or whatever