Understand the contract
unittest organizes checks into TestCase methods whose names begin with test. Assertions such as assertEqual compare results and report useful failures. Each test should verify an observable requirement, including meaningful boundary cases rather than only a happy path.
A loader collects tests into a suite, and a result object records outcomes. A failure is usually an unmet assertion; an error is another unexpected exception. These scripts use TestResult directly to show stable counts without the timing text produced by the default text runner.
Follow the runtime behavior
setUp runs before each test method, providing fresh state. Use tearDown or addCleanup for resources that need release. Do not make one test depend on another running first; the suite should remain correct when a test is run independently.
In ordinary projects run discovery with python -m unittest discover. The examples instead build their own suites so they work as standalone scripts and do not inspect surrounding files or command-line arguments.
Apply it and practise
Test meaningful behavior: normal results, expected exceptions, and independent state. Keep network calls and wall-clock timing out of small unit tests, replacing dependencies with deterministic fakes where appropriate.
Exercise: test a divide function with a normal quotient and a zero divisor using assertRaises. Add a boundary case for a zero numerator. Verify testsRun is three and both failures and errors are empty.
Syntax
class ExampleTests(unittest.TestCase):
def test_result(self):
self.assertEqual(2 + 2, 4)Examples
Run one deterministic test
Use a test case to preserve a small function's expected behavior during refactoring.
import unittest
def double(value):
return value * 2
class DoubleTests(unittest.TestCase):
def test_positive(self):
self.assertEqual(double(3), 6)
suite = unittest.defaultTestLoader.loadTestsFromTestCase(DoubleTests)
result = unittest.TestResult()
suite.run(result)
print(result.testsRun, result.wasSuccessful())- The loader finds test_positive. suite.run records its outcome, and the final print reports the number of tests and whether any failed or errored.
- Use a test case to preserve a small function's expected behavior during refactoring.
- This one input does not prove all multiplication behavior; add cases that reflect the actual contract.
- Expected output: 1 True
Verify an expected exception
Use this test to protect a validation boundary against accidental acceptance of zero.
import unittest
def positive(value):
if value <= 0:
raise ValueError("must be positive")
return value
class ValidationTests(unittest.TestCase):
def test_zero(self):
with self.assertRaisesRegex(ValueError, "must be positive"):
positive(0)
result = unittest.TestResult()
unittest.defaultTestLoader.loadTestsFromTestCase(ValidationTests).run(result)
print(result.testsRun, len(result.failures), len(result.errors))- assertRaisesRegex succeeds only when the block raises ValueError with a matching message. An expected exception therefore counts as a passing test.
- Use this test to protect a validation boundary against accidental acceptance of zero.
- Overly exact message matching can make tests brittle; match the meaningful part of the public diagnostic.
- Expected output: 1 0 0
Start every test with fresh state
Use fresh fixtures for mutable state shared by several related test scenarios.
import unittest
class BasketTests(unittest.TestCase):
def setUp(self):
self.items = []
def test_add(self):
self.items.append("book")
self.assertEqual(self.items, ["book"])
def test_empty(self):
self.assertEqual(self.items, [])
result = unittest.TestResult()
unittest.defaultTestLoader.loadTestsFromTestCase(BasketTests).run(result)
print(result.testsRun, result.wasSuccessful())- setUp creates a new list for each test instance. The append performed by test_add cannot leak into test_empty, regardless of test order.
- Use fresh fixtures for mutable state shared by several related test scenarios.
- For files or other external resources, allocating fresh state also requires reliable cleanup; this in-memory list needs none.
- Expected output: 2 True
Best practices
- In ordinary projects run discovery with python -m unittest discover. The examples instead build their own suites so they work as standalone scripts and do not inspect surrounding files or command-line arguments.
- Test meaningful behavior: normal results, expected exceptions, and independent state. Keep network calls and wall-clock timing out of small unit tests, replacing dependencies with deterministic fakes where appropriate.
Runtime & versions
Python interpreter. Feature availability depends on the language and runtime version used by your project; consult the official reference below.
Python language reference