Back to Python

Python Unit Testing

Introduction to Unit Testing

Unit testing is a method of testing individual units of source code to determine if they are fit for use. Python's unittest module provides tools for constructing and running tests.

# test_calculator.py
import unittest

def add(a, b):
    return a + b

class TestCalculator(unittest.TestCase):
    def test_add(self):
        self.assertEqual(add(2, 3), 5)
        self.assertEqual(add(-1, 1), 0)
        self.assertEqual(add(0, 0), 0)

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

# Run with: python -m unittest test_calculator.py

This simple test case demonstrates the basic structure of unit tests in Python. The unittest module provides a rich set of assertions for verifying expected behavior.

Test Organization

Proper test organization is crucial for maintainable test suites. Python projects typically follow these conventions:

# Project structure
project/
├── mypackage/
│ ├── __init__.py
│ ├── module1.py
│ └── module2.py
└── tests/
    ├── __init__.py
    ├── test_module1.py
    └── test_module2.py

# test_module1.py example
import unittest
from mypackage.module1 import some_function

class TestModule1(unittest.TestCase):
    def setUp(self):
        # Runs before each test method
        self.test_data = [1, 2, 3]

    def tearDown(self):
        # Runs after each test method
        del self.test_data

    def test_some_function(self):
        result = some_function(self.test_data)
        self.assertIsInstance(result, list)
        self.assertEqual(len(result), 3)

The setUp() and tearDown() methods allow you to define instructions that will be executed before and after each test method.

Common Assertions

The unittest module provides many assertion methods to check for and report failures:

class TestAssertions(unittest.TestCase):
    def test_assertions(self):
        # Equality
        self.assertEqual(3 + 2, 5)
        self.assertNotEqual(3, 5)

        # Boolean conditions
        self.assertTrue(1 == 1)
        self.assertFalse(1 == 2)

        # Identity
        self.assertIs(None, None)
        self.assertIsNot(1, True)

        # Membership
        self.assertIn(3, [1, 2, 3])
        self.assertNotIn(4, [1, 2, 3])

        # Exceptions
        with self.assertRaises(ValueError):
            int('not a number')

        # Approximate equality
        self.assertAlmostEqual(0.1 + 0.2, 0.3, places=7)
        self.assertNotAlmostEqual(0.1 + 0.2, 0.4, places=7)

These assertions help verify various conditions in your tests, making it easy to check that your code behaves as expected.

Advanced Testing Techniques

For more complex scenarios, Python offers several advanced testing techniques:

# Mocking and patching
from unittest.mock import Mock, patch

class TestAdvanced(unittest.TestCase):
    def test_mock(self):
        # Create a mock object
        mock = Mock()
        mock.method.return_value = 42
        self.assertEqual(mock.method(), 42)

    @patch('os.getcwd')
    def test_patch(self, mock_getcwd):
        mock_getcwd.return_value = '/fake/directory'
        self.assertEqual(os.getcwd(), '/fake/directory')

    def test_subtests(self):
        # Parameterized testing with subtests
        for a, b, expected in [(1, 1, 2),
                           (2, 3, 5),
                           (0, 0, 0)]:
            with self.subTest(a=a, b=b, expected=expected):
                self.assertEqual(add(a, b), expected)

    @unittest.skip("demonstrating skipping")
    def test_skip(self):
        self.fail("shouldn't happen")

    @unittest.skipIf(True, "conditionally skipped")
    def test_skip_if(self):
        self.fail("shouldn't happen")

These techniques allow you to test complex scenarios, isolate components, and manage test execution more effectively.

Alternative Testing Frameworks

While unittest is powerful, Python offers other testing frameworks with different features:

# pytest example (install with: pip install pytest)
# test_with_pytest.py
def add(a, b):
    return a + b

def test_add():
    assert add(2, 3) == 5

# Run with: pytest test_with_pytest.py

# doctest example (tests in docstrings)
def multiply(a, b):
    """Multiply two numbers.
    >>> multiply(2, 3)
    6
    >>> multiply('a', 3)
    'aaa'
    """
    return a * b

if __name__ == "__main__":
    import doctest
    doctest.testmod()

# Run with: python -m doctest -v example.py

pytest offers a more concise syntax and powerful features, while doctest allows you to embed tests in docstrings.

Python Unit Testing Videos

Master Python unit testing with these handpicked YouTube tutorials:

unittest Basics

Learn the fundamentals of unittest:

pytest Framework

Modern testing with pytest:

Mocking & Patching

Isolating components for testing:

Testing Strategies

Effective testing approaches:

Python Unit Testing Quiz