Debug School

rakesh kumar
rakesh kumar

Posted on

How to Re-using old test code in unittest

Some users will find that they have existing test code that they would like to run from unittest, without converting every old test function to a TestCase subclass.

For this reason, unittest provides a FunctionTestCase class. This subclass of TestCase can be used to wrap an existing test function. Set-up and tear-down functions can also be provided.

Given the following test function:

def testSomething():
    something = makeSomething()
    assert something.name is not None
    # ...
Enter fullscreen mode Exit fullscreen mode

one can create an equivalent test case instance as follows:

testcase = unittest.FunctionTestCase(testSomething)
Enter fullscreen mode Exit fullscreen mode

If there are additional set-up and tear-down methods that should be called as part of the test case’s operation, they can also be provided like so:

testcase = unittest.FunctionTestCase(testSomething,
                                     setUp=makeSomethingDB,
                                     tearDown=deleteSomethingDB)
Enter fullscreen mode Exit fullscreen mode

To make migrating existing test suites easier, unittest supports tests raising AssertionError to indicate test failure. However, it is recommended that you use the explicit TestCase.fail*() and TestCase.assert*() methods instead, as future versions of unittest may treat AssertionError differently.

Note Even though FunctionTestCase can be used to quickly convert an existing test base over to a unittest-based system, this approach is not recommended. Taking the time to set up proper TestCase subclasses will make future test refactorings infinitely easier.
In some cases, the existing tests may have been written using the doctest module. If so, doctest provides a DocTestSuite class that can automatically build unittest.TestSuite instances from the existing doctest-based tests.

Reusing old test code in unittest can help you efficiently build upon existing tests, maintain a consistent test suite, and save time. Here's a checklist for reusing old test code in unittest, along with examples and expected outputs for each item:

Create a Base Test Class:

Create a base test class that contains common setup and utility methods for multiple test cases.

import unittest

class BaseTestCase(unittest.TestCase):
    def setUp(self):
        # Common setup steps

    def tearDown(self):
        # Common cleanup steps
Enter fullscreen mode Exit fullscreen mode

Inherit from the Base Test Class:

Inherit your test cases from the base test class to inherit its setup and utility methods.

class YourTestCase(BaseTestCase):
Enter fullscreen mode Exit fullscreen mode

Override Base Test Methods:

If needed, override base test methods to customize their behavior for specific test cases.

def setUp(self):
    super().setUp()  # Call the base class's setUp method
    # Additional setup for this test case
Enter fullscreen mode Exit fullscreen mode

Reuse Utility Methods:

Utilize utility methods defined in the base class within your test methods.

def test_something(self):
    self.common_utility_method()
    # Test-specific assertions
Enter fullscreen mode Exit fullscreen mode

Create a Test Suite:

Organize test cases into a test suite to execute multiple test cases together.

def suite():
    suite = unittest.TestLoader().loadTestsFromTestCase(YourTestCase)
    return suite
Enter fullscreen mode Exit fullscreen mode

Use Test Discovery or Test Runner:

Use test discovery or a test runner to execute test suites that include multiple test cases.

python -m unittest discover
Enter fullscreen mode Exit fullscreen mode

Example:

Here's an example that illustrates the checklist for reusing old test code in unittest:

import unittest

class MathOperations:
    @staticmethod
    def add(x, y):
        return x + y

class BaseTestCase(unittest.TestCase):
    def setUp(self):
        self.math = MathOperations()

    def tearDown(self):
        self.math = None

class AdditionTestCase(BaseTestCase):
    def test_add_positive_numbers(self):
        result = self.math.add(2, 3)
        self.assertEqual(result, 5, "Adding 2 and 3 should result in 5.")

    def test_add_negative_numbers(self):
        result = self.math.add(-2, -3)
        self.assertEqual(result, -5, "Adding -2 and -3 should result in -5.")

class SubtractionTestCase(BaseTestCase):
    def test_subtract_positive_numbers(self):
        result = self.math.subtract(5, 2)
        self.assertEqual(result, 3, "Subtracting 2 from 5 should result in 3.")

if __name__ == "__main__":
    unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromModule())
Enter fullscreen mode Exit fullscreen mode

Expected Output:

When you run the above test script, unittest will discover and run the test cases. Here's the expected output:

test_add_negative_numbers (main.SubtractionTestCase) ... ok
test_add_positive_numbers (main.AdditionTestCase) ... ok
test_subtract_positive_numbers (main.SubtractionTestCase) ... ok
Enter fullscreen mode Exit fullscreen mode
----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK
Enter fullscreen mode Exit fullscreen mode

In this output:

"ok" next to each test method indicates that all tests passed.
"Ran 3 tests" shows the number of test methods executed.
"OK" at the end means all tests passed successfully.
This checklist simplifies the process of reusing and extending existing test code in unittest, ensuring that your test suite is well-organized and efficient.

Refrence

Top comments (0)