Writing and Running Testsο
π§ͺ This guide explains how to write and run tests using
pytest, following the structure used in the template-project.
Writing good tests helps you avoid bugs, refactor safely, and ensure your code does what you expect β even weeks or months later.
π Where Tests Goο
All test code lives in the tests/ directory at the root of the project.
Each Python file in this folder starts with
test_Each test function inside starts with
test_You can organize tests by topic or module:
test_utils.py,test_readers.py, etc.
βοΈ Writing Your First Testο
Tests are written as plain Python functions and typically use assertions to check behavior:
# tests/test_math.py
def test_addition():
assert 1 + 1 == 2
To test your own project modules, just import them like normal:
# tests/test_processors.py
from template_project.processors import convert_units_var
def test_convert_units_basic():
result = convert_units_var(10, "m", "km")
assert result == 0.01
π‘ All test functions must start with
test_sopytestcan discover them.
βΆοΈ Running Tests Locallyο
Make sure youβve installed the dev dependencies:
pip install -e ".[dev]"
Then run:
pytest
This will automatically find and run any test_*.py files under the tests/ folder.
To run a specific test file:
pytest tests/test_processors.py
To run a specific test function:
pytest tests/test_processors.py::test_convert_units_basic
π Recommended Conventionsο
Group related tests by file (e.g.
test_utilities.py,test_standardise.py)Name test functions to reflect what they check (e.g.
test_raises_on_invalid_units)Use fixtures or test classes to share setup code when needed
Keep each test focused on one thing
π Checking Test Coverageο
Test coverage shows which lines of code are executed during testing. Higher coverage generally means better testing, but 100% coverage doesnβt guarantee perfect tests.
Quick Coverage Checkο
# Basic coverage report in terminal
pytest --cov=template_project --cov-report=term-missing
This shows:
Percentage covered for each file
Missing lines that arenβt tested
Detailed Coverage Analysisο
For a comprehensive view, generate an HTML report:
pytest --cov=template_project --cov-report=html
Then open htmlcov/index.html in your browser.
Reading Coverage Reportsο
Terminal output example:
Name Stmts Miss Cover Missing
-----------------------------------------------------
template_project/processors/units.py 20 3 85% 63, 96-97
template_project/utils.py 78 24 69% 79-80, 113-120
-----------------------------------------------------
TOTAL 354 76 79%
What this means:
Stmts: Total executable statements
Miss: Statements not covered by tests
Cover: Percentage covered
Missing: Specific line numbers not tested
HTML report shows:
π’ Green lines: Covered by tests
π΄ Red lines: Not covered by tests
π‘ Yellow lines: Partially covered (e.g., branches)
Coverage Guidelinesο
Target coverage levels:
80%+: Good coverage for most projects
90%+: Excellent coverage
100%: Often impractical (includes error handling, edge cases)
Focus on:
Core business logic functions
Complex algorithms and calculations
Error handling paths
Public API functions
Less critical to test:
Simple getters/setters
Third-party library integration
Configuration/setup code
Run pytest locally before pushing so you catch test failures early. The CI test job also runs the suite on every pull request. See the linting & formatting guide for the ruff checks CI enforces.
Summary Cheatsheetο
Task |
Command |
|---|---|
Run all tests |
|
Run specific test file |
|
Run specific test |
|
Coverage report (terminal) |
|
Coverage report (HTML) |
|
Install test tools |
|
β Tests help you make confident changes. Use them early, and use them often!