Currently I have many similar unittest TestCases. Each TestCase contains both data (input values + expected output values) and logic (call the SUT and compare the actual output with the expected output).
I would like to separate the data from the logic. Thus I want a base class that only contains the logic and a derived class that contains only the data. I came up with this so far:
import unittest
class MyClass():
def __init__(self, input):
self.input = input
def get_result(self):
return self.input * 2
class TestBase(unittest.TestCase):
def check(self, input, expected_output):
obj = self.class_under_test(input)
actual_output = obj.get_result()
self.assertEqual(actual_output, expected_output)
def test_get_result(self):
for value in self.values:
self.check(value[0], value[1])
class TestMyClass(TestBase):
def __init__(self, methodName='runTest'):
unittest.TestCase.__init__(self, methodName)
self.class_under_test = MyClass
self.values = [(1, 2), (3, 6)]
unittest.main(exit = False)
But this fails with the following error:
AttributeError: 'TestBase' object has no attribute 'values'
Two questions:
A little late here but recently came into the need to have unit test inheritence
The most elegant solution that I could find is this:
First - you need a base test class
class MyBaseUnitTest(unittest.TestCase):
__test__ = False
def test_someting(self):
...
def test_something_else(self):
...
then to inherit that class and run tests:
class TestA(MyBaseUnitTest):
__test__ = True
def test_feature(self):
pass
def test_feature2(self):
pass
This is the best, and easiset way to have a single viewset inheritence.
The issue I found with multiple inheritance is that when you try invoke methods like setUp()
it will not be called on the base test class, so you have to call it in each class you write that extends the base class.
I hope that this will help somebody with this somewhere in the future.
BTW: This was done in python3 - I do not know how it will react in python2
UPDATE:
This is probably better and more pythonic
class MyBaseUnitTest(object):
def test_someting(self):
...
def test_something_else(self):
...
class TestA(MyBaseUnitTest, unittest.TestCase):
def test_feature(self):
pass
def test_feature2(self):
pass
So long as the base test class does not extend "unittest.TestCase", the test runner will not resolve these tests and they will not run in the suite. They will only run where the base class extends them.
To make this work as expected, you minimally need to:
__init__(self, methodName="runTest")
super(TestMyClass, self).__init__(methodName)
def test_get_result(self):
As for whether it's good design, remember, your tests act in part as documentation for how your code is meant to work. If you've got all the work hidden away in TestCase instance state, what it does will not be as obvious. You might be better off, say, writing a mixin class that has custom assertions that take inputs and expected outputs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With