[Fixed]-How can I add a test method to a group of Django TestCase-derived classes?

5👍

I faced a similar problem. I couldn’t prevent the test method in the base class being executed but I ensured that it did not exercise any actual code. I did this by checking for an attribute and returning immediately if it was set. This attribute was only set for the Base class and hence the tests ran everywhere else but the base class.

class SharedTest(TestCase):
    def setUp(self):
        self.do_not_run = True

    def test_foo(self):
        if getattr(self, 'do_not_run', False):
            return
        # Rest of the test body.

class OneTestCase(SharedTest):
    def setUp(self):
        super(OneTestCase, self).setUp()
        self.do_not_run = False

This is a bit of a hack. There is probably a better way to do this but I am not sure how.

Update

As sdolan says a mixin is the right way. Why didn’t I see that before?

Update 2

(After reading comments) It would be nice if (1) the superclass method could avoid the hackish if getattr(self, 'do_not_run', False): check; (2) if the number of tests were counted accurately.

There is a possible way to do this. Django picks up and executes all test classes in tests, be it tests.py or a package with that name. If the test superclass is declared outside the tests module then this won’t happen. It can still be inherited by test classes. For instance SharedTest can be located in app.utils and then used by the test cases. This would be a cleaner version of the above solution.

# module app.utils.test
class SharedTest(TestCase):
    def test_foo(self):
        # Rest of the test body.

# module app.tests
from app.utils import test
class OneTestCase(test.SharedTest):
    ...

32👍

You could use a mixin by taking advantage that the test runner only runs tests inheriting from unittest.TestCase (which Django’s TestCase inherits from.) For example:

class SharedTestMixin(object):
    # This class will not be executed by the test runner (it inherits from object, not unittest.TestCase.
    # If it did, assertEquals would fail , as it is not a method that exists in `object`
    def test_common(self):
         self.assertEquals(1, 1)


class TestOne(TestCase, SharedTestMixin):
    def test_something(self):
         pass

    # test_common is also run

class TestTwo(TestCase, SharedTestMixin):
    def test_another_thing(self):
        pass

    # test_common is also run

For more information on why this works do a search for python method resolution order and multiple inheritance.

Leave a comment