Reputation: 2283
I need to use unittest
in python to write some tests. I am testing the behavior of 2 classes, A
and B
, that have a lot of overlap in behavior because they are both subclasses of C
, which is abstract. I would really like to be able to write 3 testing classes: ATestCase
, BTestCase
, and AbstractTestCase
, where AbstractTestCase
defines the common setup logic for ATestCase
and BTestCase
, but does not itself run any tests. ATestCase
and BTestCase
would be subclasses of AbstractTestCase
and would define behavior/input data specific to A
and B
.
Is there a way to create an abstract class via python unittest
that can take care of setup functionality by inheriting from TestCase, but not actually run any tests?
Upvotes: 4
Views: 2322
Reputation: 11188
I tried Łukasz’s answer and it works, but I don’t like OK (SKIP=<number>)
messages. For my own desires and aims for having a test suite I don’t want me or someone to start trusting any particular number of skipped tests, or not trusting and digging into the test suite and asking why something was skipped, and always?, and on purpose? For me that’s a non-starter.
I happen to use nosetests exclusively, and by convention test classes starting with _
are not run, so naming my base class _TestBaseClass
is sufficient.
I tried this in Pycharm with Unittests and py.test and both of those tried to run my base class and its tests resulting in errors because there’s no instance data in the abstract base class. Maybe someone with specific knowledge of either of those runners could make a suite, or something, that bypasses the base class.
Upvotes: 2
Reputation: 23223
Sure, construct like that will surely work:
class BaseTestCase(unittest.TestCase):
def setUp(self):
pass # common teardown
def tearDown(self):
pass # common teardown
class ATestCase(BaseTestCase):
def test1(self):
pass
class BTestCase(BaseTestCase):
def test1(self):
pass
If knowledge from ATestCase
or BTestCase
is required in BaseTestCase
simply override some method in subclasses but use it in superclass.
class BaseTestCase(unittest.TestCase):
def setUp(self):
self.instance = self._create_instance()
def _create_instance(self):
raise NotImplementedError()
class ATestCase(BaseTestCase):
def _create_instance(self):
return A()
class BestCase(BaseTestCase):
def _create_instance(self):
return B()
Note that if any test_(self)
methods will be implemented in BaseTestCase, they'll run (and fail due to failing setUp) when discovered by automated runners.
As a workaround you may use skipTest
in your setUp clause in abstract test and override it in subclasses.
class BaseTestCase(unittest.TestCase):
def setUp(self):
self.instance = self._create_instance()
def _create_instance(self):
self.skipTest("Abstract")
def test_fromBase(self):
self.assertTrue(True)
Note that skipping test_fromBase
(e.g. via decorator) won't be good, since 'test should be skipped' logic will be inherited by all subclasses.
Upvotes: 3