Python unittest

Python unittest is used to write unit test cases for testing our code programmatically. Properly written test cases help us to test if the project/application requirements are met.

In this tutorial, we will learn how to use unittest library to write test cases for a Calculator application.

unittest Example

Let us create a Calculator program calc.py, which contains two methods: add() and subtract() as shown in the following.

calc.py

</>
Copy
def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

Now, we shall write a class test_calc.py that inherits unittest.TestCase, contains two tests, one for each of the method in calc.py.

test_calc.py

</>
Copy
import unittest
import calc

class TestCalc(unittest.TestCase):

    def test_add(self):
        self.assertEqual(calc.add(4, 8), 12)

    def test_subtract(self):
        self.assertEqual(calc.subtract(8, 2), 6)

if __name__ == '__main__':
    unittest.main()

Output

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Test Case Class (TestCalc) Breakdown

Let us understand test_calc.py in the above example statement by statement.

1. Import unittest

</>
Copy
import unittest

unittest is a builtin library. To use TestCase class, we must import unittest.

2. Import your code

</>
Copy
import calc

Since we are writing test cases in a separate Python File, import your code that you would like to test. For this example, both calc.py, and test_calc.py are in the same location.

3. Subclass TestCase

</>
Copy
class TestCalc(unittest.TestCase):

The class we are writing to test must inherit TestCase class of unittest library, so that, we can access the assert methods and many more functionalities, which we shall see in the following tutorials in detail.

4. Write Unit Test

</>
Copy
def test_add(self):
    self.assertEqual(calc.add(4, 8), 12)

The method name for a unit test must start with the word test.

Inside the method, we may call an assert method. In this example, we called assertEqual() method which asserts if the arguments are equal in value. assertEqual() method is present in unittest.TestCase class, which we inherited for our class TestCalc.

In this method we are testing add() method of calc.py. add(4, 8) must return 12 as per our requirement. Therefore, we are asserting that the value returned by add(4, 8) and 12 must be equal, using assertEqual() method.

Similarly, the following method is used to test calc.subtract() method.

</>
Copy
def test_subtract(self):
    self.assertEqual(calc.subtract(8, 2), 6)

5. Run Tests

</>
Copy
if __name__ == '__main__':
    unittest.main()

The above code starts running the test cases.

6. Output

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

The two dots in the first line represent the number of test cases run.

The description Ran 2 tests in 0.000s describes the number of test run and the time taken to run these tests.

The text OK represents that all the test cases are passed.

Multiple Assertions in a TestCase

In our previous example, we had methods test_add() and test_subtract() which had only one assert statement in each. But, we can have as many assert statements as required for testing the respective method/requirement.

For example, let us say, we would like to test all the edge cases for calc.add() method, like: adding two positive numbers; two negative numbers; one positive and one negative number; one zero and one non-zero number. Similarly, we write these edge scenarios for testing subtract() method.

calc.py remains the same as in the example above. We are only modifying our tests to be thorough.

test_calc.py

</>
Copy
import unittest
import calc

class TestCalc(unittest.TestCase):

    def test_add(self):
        self.assertEqual(calc.add(4, 8), 12)
        self.assertEqual(calc.add(4, -8), -4)
        self.assertEqual(calc.add(-4, -8), -12)
        self.assertEqual(calc.add(4, 0), 4)

    def test_subtract(self):
        self.assertEqual(calc.subtract(8, 2), 6)
        self.assertEqual(calc.subtract(8, -2), 10)
        self.assertEqual(calc.subtract(-8, -2), -6)
        self.assertEqual(calc.subtract(8, 0), 8)

if __name__ == '__main__':
    unittest.main()

Output

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Failed TestCase

Now, let us modify test_add() in such a way that one of the assertion statements fail. This is only to observe how the output would be when a test case fails.

test_calc.py

</>
Copy
import unittest
import calc

class TestCalc(unittest.TestCase):

    def test_add(self):
        self.assertEqual(calc.add(4, 8), 5)

    def test_subtract(self):
        self.assertEqual(calc.subtract(8, 2), 6)

if __name__ == '__main__':
    unittest.main()

Output

F.
======================================================================
FAIL: test_add (__main__.TestCalc)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/tutorialkart/Desktop/Projects/PythonTutorial/test_calc.py", line 7, in test_add
    self.assertEqual(calc.add(4, 8), 5)
AssertionError: 12 != 5

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=1)

The output is self explanatory that there is one failure with AssertionError at the statement self.assertEqual(calc.add(4, 8), 5).