Fundamentals 7 min read

Using Python's unittest Module for Unit Testing, Reporting, and CI Integration

This article introduces Python's built‑in unittest framework, explains core concepts such as TestCase, TestSuite, TestLoader, and TestRunner, demonstrates how to write test cases, generate HTML and XML reports with HTMLTestRunner and xmlrunner, and shows parameterized testing with nose‑parameterized for CI pipelines.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Using Python's unittest Module for Unit Testing, Reporting, and CI Integration

Python provides a built‑in unit testing framework called unittest , which includes utilities for defining test cases ( TestCase ), grouping them into suites ( TestSuite ), loading them ( TestLoader ), and running them with a test runner ( TestRunner ) that records results in a TestResult object.

A simple example demonstrates a test class inheriting from unittest.TestCase with setUp , tearDown , class‑level setUpClass / tearDownClass , and two test methods using self.assertEqual :

import unittest
class MyTest(unittest.TestCase):
    def setUp(self):
        print('22222')
    def tearDown(self):
        print('111')
    @classmethod
    def setUpClass(cls):
        print('33333')
    @classmethod
    def tearDownClass(cls):
        print('4444444')
    def test_a_run(self):
        self.assertEqual(1, 1)
    def test_b_run(self):
        self.assertEqual(2, 2)

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

Common assertion methods such as assertEqual , assertNotEqual , assertTrue , assertFalse , assertIsNone , assertIn , etc., are listed for reference.

To generate an HTML test report, the third‑party HTMLTestRunner module can be installed and used. The following script creates a test suite, adds a specific test, and writes the results to res.html :

import HTMLTestRunner, unittest
class MyTest(unittest.TestCase):
    def setUp(self):
        print(22222)
    def tearDown(self):
        print('111')
    def test_run(self):
        self.assertIs(1, 1)
    # additional test methods ...

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(MyTest('test_run'))
    fp = open('res.html', 'wb')
    runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title='API Test Report', description='Test Details')
    runner.run(suite)

When many modules contain numerous test files, unittest.defaultTestLoader.discover can automatically locate all files matching a pattern (e.g., test_*.py ) and add their cases to a suite:

import unittest, HTMLTestRunner
suite = unittest.TestSuite()
all_cases = unittest.defaultTestLoader.discover('.', pattern='test_*.py')
for case in all_cases:
    suite.addTests(case)
fp = open('res.html', 'wb')
runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title='All Tests', description='Combined Test Results')
runner.run(suite)

For continuous integration with Jenkins, an XML report is required. The xmlrunner package produces such reports, which Jenkins can consume:

import unittest, xmlrunner
class My(unittest.TestCase):
    def test1(self, a, b, c):
        self.assertEqual(a + b, c)

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(My))
    runner = xmlrunner.XMLTestRunner(output='report')
    runner.run(suite)

Parameterized testing avoids writing many similar test methods. The third‑party nose‑parameterized module allows a list of argument tuples to be expanded into separate test runs:

pip install nose-parameterized
import unittest
from nose_parameterized import parameterized
class My(unittest.TestCase):
    @parameterized.expand([
        (1, 2, 3),
        (1, 2, 3),
        (1, 2, 3),
        (1, 2, 4)
    ])
    def test1(self, a, b, c):
        self.assertEqual(a + b, c)

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

The article concludes with screenshots of the generated HTML and XML reports and a QR code for sharing.

PythonUnit TestingCIunittestparameterizedHTMLTestRunnerxmlrunner
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.