I currently have a few unit tests which share a common set of tests. Here\'s an example:
import unittest
class BaseTest(unittest.TestCase):
def testCo
Matthew Marshall's answer is great, but it requires that you inherit from two classes in each of your test cases, which is error-prone. Instead, I use this (python>=2.7):
class BaseTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
if cls is BaseTest:
raise unittest.SkipTest("Skip BaseTest tests, it's a base class")
super(BaseTest, cls).setUpClass()
Do not use multiple inheritance, it will bite you later.
Instead you can just move your base class into the separate module or wrap it with the blank class:
class BaseTestCases:
class BaseTest(unittest.TestCase):
def testCommon(self):
print('Calling BaseTest:testCommon')
value = 5
self.assertEqual(value, 5)
class SubTest1(BaseTestCases.BaseTest):
def testSub1(self):
print('Calling SubTest1:testSub1')
sub = 3
self.assertEqual(sub, 3)
class SubTest2(BaseTestCases.BaseTest):
def testSub2(self):
print('Calling SubTest2:testSub2')
sub = 4
self.assertEqual(sub, 4)
if __name__ == '__main__':
unittest.main()
The output:
Calling BaseTest:testCommon
.Calling SubTest1:testSub1
.Calling BaseTest:testCommon
.Calling SubTest2:testSub2
.
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK
A way I've thought of solving this is by hiding the test methods if the base class is used. This way the tests aren't skipped, so the test results can be green instead of yellow in many test reporting tools.
Compared to the mixin method, ide's like PyCharm won't complain that unit test methods are missing from the base class.
If a base class inherits from this class, it will need to override the setUpClass
and tearDownClass
methods.
class BaseTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls._test_methods = []
if cls is BaseTest:
for name in dir(cls):
if name.startswith('test') and callable(getattr(cls, name)):
cls._test_methods.append((name, getattr(cls, name)))
setattr(cls, name, lambda self: None)
@classmethod
def tearDownClass(cls):
if cls is BaseTest:
for name, method in cls._test_methods:
setattr(cls, name, method)
cls._test_methods = []
You can add __test__ = False
in BaseTest class, but if you add it, be aware that you must add __test__ = True
in derived classes to be able to run tests.
import unittest
class BaseTest(unittest.TestCase):
__test__ = False
def testCommon(self):
print 'Calling BaseTest:testCommon'
value = 5
self.assertEquals(value, 5)
class SubTest1(BaseTest):
__test__ = True
def testSub1(self):
print 'Calling SubTest1:testSub1'
sub = 3
self.assertEquals(sub, 3)
class SubTest2(BaseTest):
__test__ = True
def testSub2(self):
print 'Calling SubTest2:testSub2'
sub = 4
self.assertEquals(sub, 4)
if __name__ == '__main__':
unittest.main()
Another option is not to execute
unittest.main()
Instead of that you can use
suite = unittest.TestLoader().loadTestsFromTestCase(TestClass)
unittest.TextTestRunner(verbosity=2).run(suite)
So you only execute the tests in the class TestClass
What are you trying to achieve? If you have common test code (assertions, template tests, etc), then place them in methods which aren't prefixed with test
so unittest
won't load them.
import unittest
class CommonTests(unittest.TestCase):
def common_assertion(self, foo, bar, baz):
# whatever common code
self.assertEqual(foo(bar), baz)
class BaseTest(CommonTests):
def testCommon(self):
print 'Calling BaseTest:testCommon'
value = 5
self.assertEquals(value, 5)
class SubTest1(CommonTests):
def testSub1(self):
print 'Calling SubTest1:testSub1'
sub = 3
self.assertEquals(sub, 3)
class SubTest2(CommonTests):
def testSub2(self):
print 'Calling SubTest2:testSub2'
sub = 4
self.assertEquals(sub, 4)
if __name__ == '__main__':
unittest.main()