Unittest#

Is an inbuilt python library for unit testing.

import unittest

Run tests#

This section provides an overview of ways and options to execute unittest scripts. Typically you can run your tests with python3 -m unittest <path to test> command - but there are some issues. Findout more at the special page.


For the purposes of this site’s approach, it is useful to have a way to run tests directly from Jupyter Notebook cells. To achieve this, you can use unittest.main(argv=[''], verbosity=2, exit=False). The following cell defines a simple test and executes it.

class SomeTest(unittest.TestCase):
    def test(self):
        self.assertEqual(10,10)

ans = unittest.main(argv=[''], verbosity=2, exit=False)
del SomeTest

unittest.TestCase descendant#

You can run tests from a specific descendant of unittest.TestCase.

The following example defines two descendants of the unittest.TestCase, but only tests from Test1 have been executed.

class Test1(unittest.TestCase):
    def test(self):
        print("test1 executed")
        self.assertEqual(10,10)

class Test2(unittest.TestCase):
    def test(self):
        print("test2 executed")
        self.assertEqual(3,3)

suite = unittest.TestLoader().loadTestsFromTestCase(Test1)
runner = unittest.TextTestRunner()
ans = runner.run(suite)
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK
test1 executed

Mocking#

Mocking is a crucial concept in testing, allowing for the simulation of program components that depend on elements difficult to reproduce in unit tests. It enables testers to isolate and control dependencies, making tests more reliable and manageable.

Find out more in specific page.


The following cell demonstrates the use of the unittest.mock.Mock object as a “test double” whose behavior is defined by the test logic. It also tracks interactions, allowing you to verify how it was used during the test.

my_mock = unittest.mock.Mock()
my_mock.return_value = "hello mock"

We defined what the mock should return - the following cell demonstrates that it returns exactly what was specified.

my_mock(a=10, b=20)
'hello mock'

We can also check which arguments were passed to the mock object during its call, which is useful for testing.

my_mock.call_args
call(a=10, b=20)

Inheritance#

Sometimes you can benefit from using inheritance in unittest. A common case is when you want to implement shared code for a set of test cases — code that serves as a template or abstraction for child classes that define the actual tests. To do this, you apply basic inheritance principles. Importantly, if you don’t want the base class itself to be executed by unittest, simply avoid inheriting it from unittest.TestCase. However, the concrete test implementations must inherit both from the base class and from unittest.TestCase to be recognized and run by unittest.


The following cell shows the implementation of the BaseClass which defines the typical for unittest methods setUpClass and tearDownClass - but it is not a child of the unittest.TestCase so it won’t be interpreted by unittest as tests to execute. It also defines two classes Test1 and Test2, which are actually tests - but they don’t implement any code - all tests and other actions are inherited from the BaseClass.

%%writefile /tmp/inheritance_unittest.py
import unittest

class BaseClass:
    @classmethod
    def setUpClass(cls):
        print("set up in:", cls)
    
    @classmethod
    def tearDownClass(cls):
        print("tear down in:", cls)
    
    def test_method(self):
        print("test in:", type(self))


class Test1(BaseClass, unittest.TestCase):
    pass


class Test2(BaseClass, unittest.TestCase):
    pass
Overwriting /tmp/inheritance_unittest.py

The following cell performs the tests shown above.

%%bash
cd /tmp
python3 -m unittest inheritance_unittest.py
set up in: <class 'inheritance_unittest.Test1'>
test in: <class 'inheritance_unittest.Test1'>
tear down in: <class 'inheritance_unittest.Test1'>
set up in: <class 'inheritance_unittest.Test2'>
test in: <class 'inheritance_unittest.Test2'>
..
tear down in: <class 'inheritance_unittest.Test2'>
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

There are 6 messages - 3 from Test1 and 3 from Test2.