Unit Testing

Introduction and structure of unit testing

A unit test tests the methods in a single class. A test case tests the response of a single method to a particular set of inputs.

To do unit testing, you have to do the following:

  • import unittest
  • import fileToBeTested or from fileToBeTested import *

    Reminder: If you use from file import * you don’t have to precede every function call with the name of the file it was imported from.

  • Write a class SomeName(unittest.TestCase). Within the class:
    • Define methods setUp(self) and tearDown(self), if desired. These are both optional.
    • Provide one or more testSomething(self) methods. You may include other methods, but the names of test methods must begin with test.
  • At the end of the test file, put unittest.main().

Role each component of unit testing play

Here’s what the unittest.main() does. For each and every method whose name begins with test, the unittest.main method calls setUp() if you have provided one. Then, it calls the test method and the tearDown() method if you have provided one. So, every test is sandwiched between setUp and tearDown.

The purpose of the setUp method is to make sure everything is in a known, pristine state before calling the test method. This way, you can make sure that the results of running one test do not affect the results of a later test.

The purpose of tearDown is to remove artifacts (such as files) that may have been created. It is used much less frequently than setUp.

Each test method should typically test only one function, though it may call that function many times. You can write multiple tests for the same function.

Here is a trivial example of a test method:

def test_add(self):
    self.assertEqual(4, add(2, 2))
    self.assertEqual(0, add(2, -2))

Assertions

If any assertion in a test method fails, the test fails and the remaining assertions in that method are not tested. Therefore, test methods should not become too long.

If the method to be tested is in a class C and you used import C rather than from C import *, you need to also use the class name, for example, self.assertEqual(4, C.add(2, 2)). The convention is to put the expected result (4) first and the function call (add) last.

Here are the most commonly used assertion methods:

  • self.assertEqual(expected, actual)
  • self.assertAlmostEqual(expected, actual) for floating point numbers
  • self.assertTrue(boolean) and assertFalse(boolean).

More assertion methods are given in an appendix.

The assertRaises function

You can test whether a function raises an exception when it is supposed to, but this method has a special form. This is necessary because arguments to a function are evaluated before the function is called. For example, if you said the following:

self.assertRaises(ZeroDivisionError, 5/0)

The argument 5/0 would be evaluated and would raise the exception before assertRaises can be called.

The solution is to pass the function name in separate from its arguments:

self.assertRaises(exception, function_name, arguments)

This allows the assertRaises function to call the function to be tested within a try-except block and handle it appropriately.

Common practices

When testing is not being done, a common idiom is to put a call to the main function as the last line in the code file, for example, main(). This causes the main method to run immediately after the file is loaded. When doing unit testing, this is undesirable. Instead, replace that line with the following:

if __name__ == '__main__':
    main()

And put the following code at the end of the test file:

unittest.main()

This way, the program will be run if loaded from the program file, and the tests will be run if loaded from the test file.

Unit test example

If provided with an int or a string, the following section of code returns a list of digits from it:

Get hands-on with 1400+ tech skills courses.