Codectionary / Developer documentation / Python

unittest

Write repeatable standard-library tests with independent cases, useful assertions, and explicit results.

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())
  1. 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.
  2. Use a test case to preserve a small function's expected behavior during refactoring.
  3. This one input does not prove all multiplication behavior; add cases that reflect the actual contract.
  4. 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))
  1. assertRaisesRegex succeeds only when the block raises ValueError with a matching message. An expected exception therefore counts as a passing test.
  2. Use this test to protect a validation boundary against accidental acceptance of zero.
  3. Overly exact message matching can make tests brittle; match the meaningful part of the public diagnostic.
  4. 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())
  1. setUp creates a new list for each test instance. The append performed by test_add cannot leak into test_empty, regardless of test order.
  2. Use fresh fixtures for mutable state shared by several related test scenarios.
  3. For files or other external resources, allocating fresh state also requires reliable cleanup; this in-memory list needs none.
  4. 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

Specifications & further reading