3

Situation 1

Suppose I have a test class that I'd like to re-use, test_doubled.py:

import unittest

class BaseTestCase(unittest.TestCase):
    def test_something(self):
        self.assertTrue(True)

It contains a singled class, BaseTestCase, that inherits from unittest.TestCase and has a single test method.

Running the test from the command line produces the following output as expected:

$ python -m unittest discover -p test_doubled.py -v
test_something (test_doubled.BaseTestCase) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Situation 2

Now suppose I add a second module, test_doubled_2.py, like so:

from test_doubled import BaseTestCase

class DerivedTestCase(BaseTestCase):
    pass

It inherits from BaseTestCase, so I expect that it will have the same test method, and that the test method will get executed. However, when I run it, I get the following output:

$ python -m unittest discover -p test_doubled_2.py -v
test_something (test_doubled.BaseTestCase) ... ok
test_something (test_doubled_2.DerivedTestCase) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

It seems to run the method twice, once for the derived class, and once for the base class. This is not what I expect at all.

Situation 3

My suspicion is that, by importing BaseTestCase from test_doubled_2.py, the whole BaseTestCase class is getting executed. This seems to be confirmed by running both test modules:

$ python -m unittest discover -p test_doubled\*.py -v
test_something (test_doubled.BaseTestCase) ... ok
test_something (test_doubled.BaseTestCase) ... ok
test_something (test_doubled_2.DerivedTestCase) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

Running both modules executes the same test method three times, when I would expect it to be executed only twice.

How can I get the test method to only execute once in Situation 2 and twice in Situation 3?


UPDATE

To clarify, the BaseTestCase should be a usable test on its own, so making it a mixin won't work. I only want to prevent it from getting executed extra times.

Here is the desired outcome:

  1. Running just the BaseTestCase test in test_doubled.py:

    $ python -m unittest discover -p test_doubled.py -v
    test_something (test_doubled.BaseTestCase) ... ok
    
    ----------------------------------------------------------------------
    Ran 1 test in 0.000s
    
    OK
    

    This already works as desired.

  2. Running just the DerivedTestCase in test_doubled_2.py:

    $ python -m unittest discover -p test_doubled_2.py -v
    test_something (test_doubled_2.DerivedTestCase) ... ok
    
    ----------------------------------------------------------------------
    Ran 2 tests in 0.000s
    
    OK
    

    It should only execute the DerivedTestCase, and not the BaseTestCase.

  3. Running both:

    $ python -m unittest discover -p test_doubled\*.py -v
    test_something (test_doubled.BaseTestCase) ... ok
    test_something (test_doubled_2.DerivedTestCase) ... ok
    
    ----------------------------------------------------------------------
    Ran 3 tests in 0.000s
    
    OK
    

    The test method is executed exactly twice, once for BaseTestcase and once for DerivedTestCase.

izrik
  • 918
  • 2
  • 9
  • 20
  • 1
    https://stackoverflow.com/questions/1323455/python-unit-test-with-base-and-sub-class, second answer. – Aleksandr Borisov Oct 27 '17 at 15:54
  • Possible duplicate of [Python unit test with base and sub class](https://stackoverflow.com/questions/1323455/python-unit-test-with-base-and-sub-class) –  Oct 27 '17 at 16:06
  • @Wyatt That's not quite what I'm asking. I still want the base test class to be usable in its own right. I have updated the question to clarify. – izrik Oct 27 '17 at 16:10
  • You could make `BaseTestCase` inherit the mixin as well. I edited my answer to reflect this but deleted it because the other answer discusses this option and some others plus the trade-offs. –  Oct 27 '17 at 16:11

2 Answers2

2

You can use a mixin like this:

# mixin.py
class TestMixin(object):

    def test_something(self):
        self.assertTrue(True)


# test_base.py
import unittest
from .mixin import TestMixin

class BaseTestCase(TestMixin, unittest.TestCase):

    pass


# test_derived.py
import unittest
from .mixin import TestMixin

class DerivedTestCase(TestMixin, unittest.TestCase):

    pass
  • Ah, yes. I see now. That does achieve the desired result. I had hoped to avoid creating more classes, but it looks like it's the best way to do it. – izrik Oct 27 '17 at 16:18
2

Don't use multiple inheritance it will bite you later.

Use a wrapping approach as suggested in https://stackoverflow.com/a/25695512/328384

harmv
  • 1,905
  • 22
  • 22