Python

Python unit test with base and sub class

25 September 2026 · 6 min read

Python unit test with base and sub class

Ensuring the robustness of object-oriented Python applications often hinges on a solid testing strategy, especially when dealing with complex class hierarchies. When you’re building systems with base classes defining core functionalities and sub classes extending or specializing those behaviors, the challenge of creating effective unit tests intensifies. A well-structured approach to a Python unit test with base and sub class not only validates individual components but also confirms that inherited behaviors function as expected and overridden methods perform correctly. This article delves into practical techniques and best practices for writing comprehensive unit tests that navigate the intricacies of inheritance, leveraging Python’s built-in unittest framework to achieve reliable and maintainable code.

Understanding Python’s unittest Framework and Inheritance

Python’s unittest module, inspired by JUnit, provides a rich framework for organizing and executing unit tests. It’s the standard library’s answer to test-driven development in Python, offering a robust set of assertions and setup/teardown methods crucial for isolating test environments. At its core, unittest operates on the concept of test cases, which are classes that inherit from unittest.TestCase and contain individual test methods starting with test_. This structure naturally lends itself to testing object-oriented designs, including those with intricate inheritance patterns.

Object-Oriented Programming (OOP) in Python heavily relies on inheritance, where a new class (sub class or derived class) can inherit attributes and methods from an existing class (base class or parent class). This mechanism promotes code reusability and establishes a clear “is-a” relationship between classes. For instance, a Vehicle base class might define common behaviors like start_engine() and stop_engine(), while a Car sub class might add specialized methods like drive() or open_trunk(). The challenge, and indeed the necessity, lies in verifying that Car correctly inherits and executes start_engine() from Vehicle, and that any overridden methods behave as intended.

Properly testing inherited behavior is paramount because a bug in a base class method can silently propagate to all its sub classes, leading to widespread issues. Conversely, a sub class might unintentionally alter inherited behavior, breaking assumptions made by other parts of the system. According to a study published by the IEEE (Institute of Electrical and Electronics Engineers), effective unit testing significantly reduces defect density in software projects, emphasizing the importance of a thorough testing strategy for complex class hierarchies. This makes a systematic approach to a Python unit test with base and sub class not just good practice, but a critical safeguard for software quality.

Designing Test Cases for Base Classes

When approaching a Python unit test with base and sub class, the first step is often to establish a solid test suite for your base classes. Base classes define the common contract and core functionalities that all derived classes are expected to adhere to. Therefore, thoroughly testing these foundational elements ensures that any sub class built upon them will inherit a stable and validated set of behaviors. This approach helps in identifying issues at the earliest possible stage, preventing them from cascading through the entire inheritance chain.

To effectively test a base class, focus on its public methods and attributes. Consider a Shape base class that might define an area() method (perhaps returning 0 by default, or raising an exception if not implemented by sub classes) and a get_name() method. Your test case, inheriting from unittest.TestCase, would instantiate the Shape class (or a concrete mock if the base class is abstract) and assert its expected behaviors. For example, you would check that get_name() returns the correct string or that calling area() behaves as specified. Utilize setUp() and tearDown() methods within your test class to manage test fixtures, ensuring that each test method runs in a clean, consistent state. The setUp() method is executed before each test method, while tearDown() runs after each, making them ideal for setting up objects or cleaning up resources.

Here’s a basic example demonstrating a base class and its corresponding unit test:

class BaseProcessor: def __init__(self, data): self.data = data self.processed_data = None def process(self): """Processes the data. Must be implemented by subclasses.""" raise NotImplementedError("Subclasses must implement 'process' method.") def get_result(self): return self.processed_data import unittest class TestBaseProcessor(unittest.TestCase): def setUp(self): self.processor = BaseProcessor([1, 2, 3]) def test_initial_data(self): self.assertEqual(self.processor.data, [1, 2, 3]) self.assertIsNone(self.processor.processed_data) def test_process_raises_not_implemented_error(self): with self.assertRaises(NotImplementedError): self.processor.process() def test_get_result_initially_none(self): self.assertIsNone(self.processor.get_result()) if __name__ == '__main__': unittest.main() 

This snippet illustrates testing the initialization of the base class and confirming that its abstract method correctly raises an NotImplementedError. This foundational testing provides a safety net for all future sub classes, guaranteeing they conform to the expected interface.

Strategies for Python Unit Test with Base and Sub Class

When you have a base class with a well-tested foundation, the next challenge is to extend these testing principles to its sub classes. A key aspect of a Python unit test with base and sub class is understanding that sub classes automatically inherit all test methods from their parent unittest.TestCase class. This means if you have a TestBaseClass, and a TestSubClass inherits from TestBaseClass, all tests defined in TestBaseClass will automatically run for instances of SubClass within TestSubClass. This powerful feature promotes test inheritance and code reusability in your test suite.

However, simple inheritance isn’t always enough. Sub classes often override base class methods, introduce new behaviors, or modify existing ones. In such cases, you need to write specific tests for these changes. When a sub class overrides a method, you might need to either override the corresponding test method in your TestSubClass to reflect the new behavior or add entirely new test methods. The goal is to ensure that the overridden method functions as expected in the context of the sub class, while still confirming that any un-overridden inherited methods continue to work correctly.

Polymorphic testing, which is central to testing class hierarchies, involves treating objects of different classes through a common interface. For example, if both Square and Circle inherit from Shape and implement an area() method, you could write a test that iterates through a list of Shape objects (which are actually Square and Circle instances) and calls area(), asserting the correct result for each. This ensures that polymorphism works as expected across your class hierarchy. For more insights on designing robust test cases, consider exploring official [later](<https://docs.python.org/3 Question & Answer :

I currently have a few unit tests which share a common set of tests. Here’s an example:

import unittest class BaseTest(unittest.TestCase): def testCommon(self): print ‘Calling BaseTest:testCommon’ value = 5 self.assertEquals(value, 5) class SubTest1(BaseTest): def testSub1(self): print ‘Calling SubTest1:testSub1’ sub = 3 self.assertEquals(sub, 3) class SubTest2(BaseTest): def testSub2(self): print ‘Calling SubTest2:testSub2’ sub = 4 self.assertEquals(sub, 4) if name == ‘main’: unittest.main() 

The output of the above is:

Calling BaseTest:testCommon .Calling BaseTest:testCommon .Calling SubTest1:testSub1 .Calling BaseTest:testCommon .Calling SubTest2:testSub2 . ———————————————————————- Ran 5 tests in 0.000s OK 

Is there a way to rewrite the above so that the very first testCommon is not called?

Instead of running 5 tests above, I want it to run only 4 tests, 2 from the SubTest1 and another 2 from SubTest2. It seems that Python unittest is running the original BaseTest on its own and I need a mechanism to prevent that from happening.


Do not use multiple inheritance, it will bite you <a href=>).

Instead you can just move your base class into the separate module or wrap it with the blank class:

class BaseTestCases: class BaseTest(unittest.TestCase): def testCommon(self): print('Calling BaseTest:testCommon') value = 5 self.assertEqual(value, 5) class SubTest1(BaseTestCases.BaseTest): def testSub1(self): print('Calling SubTest1:testSub1') sub = 3 self.assertEqual(sub, 3) class SubTest2(BaseTestCases.BaseTest): def testSub2(self): print('Calling SubTest2:testSub2') sub = 4 self.assertEqual(sub, 4) if __name__ == '__main__': unittest.main() 

The output:

Calling BaseTest:testCommon .Calling SubTest1:testSub1 .Calling BaseTest:testCommon .Calling SubTest2:testSub2 . ---------------------------------------------------------------------- Ran 4 tests in 0.001s OK