unittest
The unittest module is Python’s built-in unit testing framework. It was inspired by JUnit and provides test automation, fixture management, and test organization through an object-oriented approach. Whether you’re writing simple assertions or complex test suites, unittest gives you the tools to verify your code works correctly.
TestCase Class
The TestCase class is the foundation of unittest. You create test cases by subclassing it and implementing methods that start with test:
import unittest
class TestMathOperations(unittest.TestCase):
def test_addition(self):
result = 2 + 3
self.assertEqual(result, 5)
Key Methods
| Method | Description |
|---|---|
setUp() | Runs before each test method. Use it to prepare test fixtures. |
tearDown() | Runs after each test method. Use it for cleanup. |
setUpClass() | Runs once before all tests in the class. Must be a classmethod. |
tearDownClass() | Runs once after all tests in the class. Must be a classmethod. |
import unittest
class Widget:
def __init__(self, name):
self.name = name
def size(self):
return (50, 50)
class WidgetTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("Setting up WidgetTestCase")
def setUp(self):
self.widget = Widget("test")
def test_default_size(self):
self.assertEqual(self.widget.size(), (50, 50))
def tearDown(self):
# cleanup if needed
pass
Assertion Methods
TestCase provides many assertion methods. These are the most commonly used:
assertEqual(first, second, msg=None)
Checks that two values are equal. This is the most frequently used assertion.
def test_equality(self):
self.assertEqual(2 + 2, 4)
self.assertEqual("hello".upper(), "HELLO")
self.assertEqual([1, 2, 3], [1, 2, 3])
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
first | any | — | The first value to compare |
second | any | — | The second value to compare |
msg | str | None | Optional message displayed on failure |
assertTrue(expr, msg=None)
Checks that an expression is truthy.
def test_truthy(self):
self.assertTrue(1 == 1)
self.assertTrue("non-empty")
self.assertTrue([1, 2]) # non-empty list is truthy
assertFalse(expr, msg=None)
Checks that an expression is falsy.
def test_falsy(self):
self.assertFalse(1 == 2)
self.assertFalse("")
self.assertFalse(None)
assertIsNone(obj, msg=None)
Checks that an object is None.
def test_none(self):
result = some_function()
self.assertIsNone(result)
assertRaises(expected_exception, callable, *args, **kwargs)
Checks that a callable raises a specific exception. Use it with a context manager for more control:
def test_raises(self):
with self.assertRaises(ValueError):
int("not a number")
with self.assertRaises(ZeroDivisionError):
x = 1 / 0
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
expected_exception | Exception | — | The exception type expected |
callable | callable | — | The function to call |
*args | any | — | Positional arguments for callable |
**kwargs | any | — | Keyword arguments for callable |
TestSuite and TestRunner
A TestSuite groups multiple tests together. A TestRunner executes the tests and reports results.
import unittest
# Create a test suite
loader = unittest.TestLoader()
suite = unittest.TestSuite()
# Load tests from a TestCase
suite.addTests(loader.loadTestsFromTestCase(WidgetTestCase))
# Or load from a module
suite.addTests(loader.loadTestsFromName('myapp.tests'))
# Run the tests
runner = unittest.TextTestRunner(verbosity=2)
result = runner.run(suite)
TextTestRunner
The default test runner. It outputs results to the console.
runner = unittest.TextTestRunner(verbosity=1)
result = runner.run(suite)
# Check results
print(f"Tests run: {result.testsRun}")
print(f"Failures: {len(result.failures)}")
print(f"Errors: {len(result.errors)}")
unittest.main()
The simplest way to run tests. It discovers all test methods in the current module and executes them:
if __name__ == '__main__':
unittest.main()
From the command line:
python -m unittest
python -m unittest -v # verbose
python -m unittest -v mymodule # specific module
python -m unittest MyTest.test_one # specific test method
python -m unittest discover # discover all tests
Command-line options
| Option | Description |
|---|---|
-v | Verbose output |
-b | Buffer stdout/stderr during tests |
-f | Stop on first failure |
-k pattern | Run tests matching pattern |
unittest.mock Submodule
For mocking, use unittest.mock. It lets you replace real objects with fake ones during testing:
from unittest.mock import Mock, patch, MagicMock
# Create a mock
mock_obj = Mock()
mock_obj.method.return_value = 42
result = mock_obj.method()
assert result == 42
mock_obj.method.assert_called_once()
# Patch a function
@patch('mymodule.some_function')
def test_something(mock_fn):
mock_fn.return_value = 'mocked'
# ...
# MagicMock automatically handles magic methods
mock_list = MagicMock()
mock_list.__getitem__.return_value = 'mocked item'
print(mock_list[0]) # mocked item
Common mock utilities:
| Class | Description |
|---|---|
Mock | A flexible mock object that creates attributes on access |
MagicMock | Mock with magic method support (for __str__, __len__, etc.) |
patch() | Decorator/context manager to replace objects temporarily |
sentinel | Creates unique sentinel objects for testing |
Skipping Tests
Sometimes you need to skip a test temporarily:
class MyTests(unittest.TestCase):
@unittest.skip("reason for skipping")
def test_skipped(self):
self.fail("this won't run")
@unittest.skipIf(condition, "reason")
def test_conditionally_skipped(self):
pass
@unittest.skipUnless(condition, "reason")
def test_only_on_condition(self):
pass