4

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?

1
  • Why don't you test C, rather than testing the same functionality in A and B? Alternatively, TestCase could be a mix-in to the test cases for A and B, so that the AbstractTestCase isn't actually discovered by unittest. Commented Feb 9, 2016 at 23:23

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I skipped in setUp by checking the class: if self.__class__ == BaseTestCase: self.skipTest("Skip base class")
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.