Learning Goals
3 min- Run all tests with
python -m unittest discover. - Understand the naming rules discovery relies on.
- Run a single file, class, or method while debugging.
- Organise tests in a
tests/folder.
Warm-Up · One Command
5 min$ python -m unittest # finds & runs every test_*.py $ python -m unittest discover # same, explicit ........F... ---------------------------------------------------------------------- Ran 12 tests in 0.04s FAILED (failures=1)
Discovery automatically finds tests by name convention (files test*.py, classes inheriting TestCase, methods test_*) so you never maintain a master list. One command runs the whole suite — the basis of running tests in CI later.
New Concept · Discovery & Targeting
14 minThe naming rules discovery uses
files must match test*.py (default pattern) classes must inherit unittest.TestCase methods must start test_ Break any of these and the test silently won't be discovered — a classic "why isn't my test running?" trap.
Discover from a folder
project/
├─ mycode/
│ └─ bank.py
└─ tests/
├─ __init__.py
├─ test_bank.py
└─ test_inventory.py
$ python -m unittest discover -s tests # search the tests/ folder
$ python -m unittest discover -s tests -p "test_*.py" # custom patternRun a subset while debugging
# one file $ python -m unittest tests.test_bank # one class $ python -m unittest tests.test_bank.TestBankAccount # one method (laser focus on the failing test) $ python -m unittest tests.test_bank.TestBankAccount.test_overdraw_raises
Useful flags
-v verbose: print each test name + ok/FAIL -f failfast: stop at the first failure -b buffer: hide print() output unless the test fails -k word run only tests whose name contains "word"
Building a suite in code (rarely needed)
import unittest from tests import test_bank suite = unittest.TestLoader().loadTestsFromModule(test_bank) unittest.TextTestRunner(verbosity=2).run(suite)
You almost never write this by hand — discovery does it. But it shows what discovery is doing under the hood.
Worked Example · A Real Project Layout
12 minshop/ ├─ shop/ │ ├─ __init__.py │ ├─ cart.py │ └─ pricing.py ├─ tests/ │ ├─ __init__.py │ ├─ test_cart.py │ └─ test_pricing.py └─ README.md
# tests/test_pricing.py import unittest from shop.pricing import apply_discount class TestPricing(unittest.TestCase): def test_no_discount_under_100(self): self.assertEqual(apply_discount(50), 50) def test_discount_over_100(self): self.assertEqual(apply_discount(200), 180)
# from the project root: $ python -m unittest discover -v test_no_discount_under_100 (tests.test_pricing.TestPricing) ... ok test_discount_over_100 (tests.test_pricing.TestPricing) ... ok test_add_item (tests.test_cart.TestCart) ... ok ... Ran 9 tests in 0.01s OK # debugging just one failing area: $ python -m unittest tests.test_pricing -v
Read the diff
The tests/ folder mirrors the package, each module has its test_* counterpart, and one command runs everything. While debugging the pricing module you narrow to just tests.test_pricing for instant feedback. This layout + discovery is the standard for every Python project — and pytest (next lesson) uses the same conventions.
Try It Yourself
13 minPut 2+ test files in a tests/ folder and run them all with one discover command.
Rename one test method to check_* instead of test_*. Confirm it silently stops running. Rename it back. (This is the #1 "my test isn't running" cause.)
Break one test. Use -k or the dotted path to run ONLY that test repeatedly while you fix it. Then run the full suite to confirm nothing else broke.
Mini-Challenge · Reorganise a Project
8 minTake one of your earlier multi-file projects. Move its code into a package folder and create a parallel tests/ folder with at least 3 test files. Get python -m unittest discover to find and run them all green.
Recap
3 minDiscovery finds tests by convention (test*.py files, TestCase classes, test_* methods) — break a name and it silently won't run. python -m unittest discover runs everything; the dotted path or -k runs a subset for debugging. Keep tests in a tests/ folder mirroring your package. That wraps up unittest; next, pytest does the same with far less boilerplate.
Vocabulary Card
- test discovery
- Auto-finding tests by naming convention, no master list needed.
- test suite
- A collection of tests run together.
- -k filter
- Run only tests whose name matches a keyword.
- failfast (-f)
- Stop at the first failure instead of running the whole suite.
Homework
4 minSet up a project with a tests/ folder containing at least 12 tests across 3 files. Document the exact commands to: run everything, run one file, run one method, and run only tests matching a keyword. Make the whole suite green.
python -m unittest discover -v # everything python -m unittest tests.test_cart # one file python -m unittest tests.test_cart.TestCart.test_add # one method python -m unittest discover -k discount # keyword filter