Running tests and discovery

unittest · Essentials · 8 min

Knowing the runner's options makes the edit-test loop fast, locally and in CI.

The command-line runner is python -m unittest:

  • python -m unittest with no arguments runs discovery: it finds test*.py files in the current directory and importable subpackages, and runs every TestCase in them.
  • python -m unittest discover -s tests -p "test_*.py" sets the start directory and file pattern explicitly.
  • Run a subset by dotted name: python -m unittest tests.test_api, tests.test_api.TestLogin, or tests.test_api.TestLogin.test_bad_password.
  • -k pattern selects tests whose names contain the substring (or match a wildcard pattern).

Useful flags:

  • -v verbose: one line per test with its name and result.
  • -f / --failfast: stop at the first failure.
  • -b / --buffer: hide stdout/stderr of passing tests.
  • --durations N (3.12+): report the N slowest tests.

For discovery, test directories must be importable: a package with __init__.py or a namespace package reachable from the start directory. The exit status is non-zero when anything fails, which is what CI relies on.

pytest can run the same tests unchanged (pytest tests/), so starting with unittest doesn't lock you in.

Example

mkdir -p demo/tests && cd demo
touch tests/__init__.py
cat > tests/test_math.py <<'EOF'
import unittest
class TestMath(unittest.TestCase):
    def test_add(self): self.assertEqual(1 + 1, 2)
    def test_mul(self): self.assertEqual(2 * 3, 6)
EOF
python -m unittest -v            # discovery from the current directory
# test_add (tests.test_math.TestMath.test_add) ... ok
# test_mul (tests.test_math.TestMath.test_mul) ... ok
# Ran 2 tests in 0.000s
# OK
python -m unittest -k mul tests.test_math    # only test_mul
python -m unittest --durations 3             # slowest tests (3.12+)
echo "exit status: $?"                       # 0 when everything passed

Remember

  • python -m unittest discovers test*.py files automatically
  • Run subsets by dotted name or -k pattern
  • -v, -f, -b and --durations tune the output

Watch out for

  • A tests folder without __init__.py that discovery can't import, so zero tests run.

Check yourself

  1. python -m unittest reports 'Ran 0 tests'. What's a likely cause?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.python.org/3/library/unittest.html#command-line-interface