'How to structure test directory to allow using subclassed TestCase inside a subdirectory

I have the following directory structure for a number of unit tests (directories advanced and basic contain multiple files with test cases implemented in them):

Tests
├── advanced
│   ├── __init__.py
│   └── advanced_test.py
├── basic
│   ├── __init__.py
│   └── basic_test.py
└── helpers.py

with the following file contents.

# helpers.py
import unittest

def determine_option():
    # Some logic that returns the option
    return 1

class CustomTestCase(unittest.TestCase):
    def __init__(self, methodName: str = ...) -> None:
        super().__init__(methodName)

        self._option = determine_option()

    def get_option(self):
        # Some custom method used in advanced test cases
        return self._option

    def customAssert(self, first, second):
        # Some custom assertion code used in advanced and basic test cases
        self.assertEqual(first, second)
# basic_test.py
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

from helpers import CustomTestCase

class BasicTest(CustomTestCase):
    # Includes test cases that use custom assertion method
    def test_pass(self) -> None:
        self.customAssert(1, 1)
# advanced_test.py
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

from helpers import CustomTestCase

class AdvancedTest(CustomTestCase):
    # Includes test cases that use custom assertion method and some further functionality (e.g. get_option())
    def test_pass(self) -> None:
        self.customAssert(self.get_option(), 1)

The outlined structure above allows me to use the test discovery functionality of python unittest.

> python -m unittest discover -p *_test.py -v
test_pass (advanced.advanced_test.AdvancedTest) ... ok
test_pass (basic.basic_test.BasicTest) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

In order to be able to import CustomTestCase from helpers.py I had to resort to the ugly and probably bad idea of adding the parent directory to sys.path. Attempting to import via from ..helpers import CustomTestCase does not play nicely with the test discovery of python unittest (ImportError: attempted relative import beyond top-level package).

How could the Tests directory be structured to allow defining such a CustomTestClass that can be used to implement the test cases in the subdirectory without resorting to the sys.path.insert hack used?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source