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
.