pytest Integration#
jamb integrates with pytest to link tests to requirements and generate traceability matrices.
Marking Tests#
Use @pytest.mark.requirement to link a test to one or more requirements:
import pytest
@pytest.mark.requirement("SRS001")
def test_single_requirement():
assert True
@pytest.mark.requirement("SRS001", "SRS002")
def test_multiple_requirements():
assert True
The marker accepts any number of item UIDs as positional arguments.
Supported Import Styles#
jamb recognizes the requirement marker in three import styles:
# Style 1: Fully qualified (recommended)
import pytest
@pytest.mark.requirement("SRS001")
def test_example(): ...
# Style 2: Import mark from pytest
from pytest import mark
@mark.requirement("SRS001")
def test_example(): ...
# Style 3: Import requirement directly
from pytest.mark import requirement
@requirement("SRS001")
def test_example(): ...
All three styles work with jamb check, pytest --jamb, and the automatic test file updates performed by jamb reorder.
Manual Test Case IDs#
By default, jamb assigns sequential test case IDs (TC001, TC002, etc.) automatically based on test order. To lock specific IDs to tests, use @pytest.mark.tc_id:
import pytest
@pytest.mark.tc_id("TC-AUTH-001")
@pytest.mark.requirement("SRS001")
def test_user_login():
"""Test with a manually assigned test case ID."""
assert True
@pytest.mark.tc_id("TC042")
@pytest.mark.requirement("SRS002")
def test_password_reset():
"""Another test with a fixed ID."""
assert True
Manual TC IDs:
Override auto-generated IDs for the marked test
Can use any format (TC001, TC-AUTH-001, TEST-42, etc.)
Reserve their number from auto-generation (e.g.,
@pytest.mark.tc_id("TC005")prevents auto-assignment of TC005)Must be unique across all tests
To convert auto-generated IDs to permanent manual IDs, use jamb lock-tc after running tests. See the lock-tc command for details.
pytest Command-Line Options#
Option |
Description |
|---|---|
|
Enable traceability checking |
|
Output test records matrix to PATH (format inferred from extension) |
|
Output traceability matrix to PATH (format inferred from extension) |
|
Fail if any test spec items lack coverage |
|
Comma-separated document prefixes to check |
|
Tester identification for matrices (default: “Unknown”) |
|
Software version for matrices (overrides pyproject.toml) |
|
Starting document prefix for full chain trace matrix (e.g., UN, SYS) |
|
Include “Traces To” column showing ancestors of starting items |
Note: All pytest CLI options override their corresponding [tool.jamb] settings in pyproject.toml. For example, --jamb-fail-uncovered on the command line takes effect even if fail_uncovered = false in the config. When no CLI flag is given, the config file value is used.
Format inference: Matrix format is automatically inferred from the file extension: .html for HTML, .json for JSON, .csv for CSV, .md for Markdown, .xlsx for Excel.
Examples#
# Enable traceability checking
pytest --jamb
# Generate HTML trace matrix (format inferred from .html extension)
pytest --jamb --jamb-trace-matrix matrix.html
# Generate markdown trace matrix
pytest --jamb --jamb-trace-matrix matrix.md
# Generate test records matrix
pytest --jamb --jamb-test-matrix test-records.html
# Generate both matrices
pytest --jamb --jamb-trace-matrix trace.html --jamb-test-matrix records.html
# Fail if requirements lack coverage
pytest --jamb --jamb-fail-uncovered
# Check specific documents only
pytest --jamb --jamb-documents SRS
# Generate matrix with IEC 62304 metadata
pytest --jamb --jamb-trace-matrix matrix.html \
--jamb-tester-id "CI Pipeline" \
--jamb-software-version "1.2.3"
# Full chain trace from user needs with ancestor column
pytest --jamb --jamb-trace-matrix matrix.html \
--trace-from UN \
--include-ancestors
The jamb_log Fixture#
The jamb_log fixture provides structured test record logging aligned with IEC 62304 §5.7.5. Use it to document test actions, expected results, actual results, and notes that appear in the traceability matrix.
Methods#
Method |
Matrix Column |
Purpose |
|---|---|---|
|
Test Actions |
What the test does (steps performed) |
|
Expected Results |
What should happen (acceptance criteria) |
|
Actual Results |
What actually happened (observed outcomes) |
|
Notes |
Free-form observations or context |
Example#
import pytest
@pytest.mark.requirement("SRS005")
def test_heart_rate_boundaries(jamb_log):
"""Test heart rate validation at boundary values."""
jamb_log.test_action("Submit heart rate at lower boundary (30 BPM)")
jamb_log.expected_result("Value is accepted as valid")
result = validate_heart_rate(30)
jamb_log.actual_result(f"validate_heart_rate(30) returned {result}")
assert result is True
jamb_log.test_action("Submit heart rate below minimum (29 BPM)")
jamb_log.expected_result("Value is rejected as invalid")
result = validate_heart_rate(29)
jamb_log.actual_result(f"validate_heart_rate(29) returned {result}")
assert result is False
jamb_log.note("Boundary values selected per risk analysis RA-005")
Automatic Failure Capture#
When a test fails, jamb automatically captures the failure message and includes it in the Notes column of the matrix. No extra code needed.
Static vs Runtime Checking#
Feature |
|
|
|
|---|---|---|---|
Runs tests |
No |
Yes |
No |
Detects |
Yes |
Yes |
Uses saved data |
Reports pass/fail status |
No |
Yes |
Uses saved data |
Captures |
No |
Yes |
Uses saved data |
Generates traceability matrix |
No |
Yes (with |
Yes |
Generates test records matrix |
No |
Yes (with |
Yes (with |
Speed |
Fast |
Depends on test suite |
Fast |
Use jamb check for quick feedback during development. Use pytest --jamb in CI for full traceability evidence. Use jamb matrix to regenerate matrices from saved coverage data without re-running tests.
Matrix Output Formats#
Matrix format is inferred from the file extension:
Format |
Extension |
Best For |
|---|---|---|
HTML |
|
Regulatory submissions, standalone viewing |
Markdown |
|
GitHub/GitLab rendering |
JSON |
|
Tooling integration, programmatic access |
CSV |
|
Spreadsheet import, large datasets |
XLSX |
|
Excel, stakeholder review |
Performance Note: When generating HTML or XLSX matrices with more than 5,000 rows, jamb emits a warning recommending CSV format for better performance and memory usage.
Format Details#
Matrix Metadata#
When using --jamb-tester-id and --jamb-software-version, the matrix includes a metadata header section with:
Software Version: The version being tested (from CLI flag,
[tool.jamb].software_version, or[project].version)Tester: Who ran the tests (from
--jamb-tester-id)Date: When the tests were executed (ISO 8601 UTC timestamp)
Environment: Test environment details (OS, Python version, platform, processor, hostname, CPU count)
Test Tools: Versions of all pytest plugins used (pytest, jamb, pytest-cov, etc.)
This metadata satisfies IEC 62304 Clause 5.7.5 requirements for software system test records.
Test Records Matrix (IEC 62304 5.7.5)#
The test records matrix is a test-centric view designed to satisfy IEC 62304 Clause 5.7.5 requirements for software system test records. Each row represents a single test execution with complete traceability to requirements.
IEC 62304 5.7.5 requires:
Test procedures or test cases
Expected results
Actual results
Pass/fail status
Tester identification
Date of testing
The jamb test records matrix provides all of these through:
Test Case column: Unique test identifier (TC001, etc.)
Expected Results column: Populated via
jamb_log.expected_result()Actual Results column: Populated via
jamb_log.actual_result()Outcome column: Pass/fail/skip status from pytest
Metadata header: Tester ID, timestamp, and software version
Requirements column: Links to verified requirements
Example output (one row per test):
Test Case |
Test Name |
Outcome |
Requirements |
Test Actions |
Expected Results |
Actual Results |
Notes |
Timestamp |
|---|---|---|---|---|---|---|---|---|
TC001 |
test_credential_validation |
passed |
SRS001 |
Submit valid credentials |
Authentication returns True |
auth_user() returned True |
Verified both auth paths |
2024-01-15T10:30:00Z |
TC002 |
test_account_lockout |
failed |
SRS002 |
Submit 3 invalid passwords |
Account is locked |
account.locked = False |
[FAILURE] AssertionError |
2024-01-15T10:30:05Z |
TC003 |
test_heart_rate_boundaries |
passed |
SRS005 |
Submit heart rate at boundary |
Value is accepted |
validate_heart_rate(30) returned True |
Boundary values per RA-005 |
2024-01-15T10:30:10Z |
Trace Matrix Example#
The trace matrix is requirement-centric, showing the full traceability chain from a starting document through the hierarchy:
Traces To |
UN |
SYS |
SRS |
Tests |
Status |
|---|---|---|---|---|---|
- |
UN001: User Authentication |
SYS001: Authentication System |
SRS001: The system shall authenticate users |
TC001: test_credential_validation [passed] |
Passed |
- |
UN001: User Authentication |
SYS001: Authentication System |
SRS002: The system shall lock accounts |
TC002: test_account_lockout [failed] |
Failed |
- |
UN002: Heart Rate Monitoring |
SYS002: Vital Signs Display |
SRS003: Display heart rate in real-time |
- |
Not Covered |
- |
UN003: Documentation |
SYS003: User Manual |
SRS099: User manual shall be provided |
- |
N/A |
Status Values:
Passed (green): All linked tests passed
Failed (red): One or more linked tests failed
Partial (orange): Mix of passed and failed tests
Skipped (amber): All linked tests were skipped (none passed, none failed)
Not Covered (yellow): No tests linked to this requirement
N/A (gray): Requirement marked as
testable: false(verified by other means)
HTML – Standalone document with inline CSS. Includes summary statistics banner, styled tables, and color-coded status. Test records matrix shows test actions, expected/actual results, and notes in separate columns. Trace matrix shows document hierarchy columns with bold UIDs and full requirement text.
Markdown – Pipe-delimited table with summary section. Test records show one row per test with semicolon-separated actions/results. Trace matrix shows document hierarchy with combined UID and text.
JSON – Structured data with arrays of test records or trace chain objects. Test records include test_actions, expected_results, actual_results, and notes arrays. Trace matrix includes nested chain objects per document level. Suitable for custom tooling.
CSV – Standard comma-separated values with summary rows at the top. Test records show one row per test. Trace matrix shows document hierarchy as separate columns. Recommended for large datasets (5,000+ rows).
XLSX – Excel workbook with summary rows, text wrapping, and color-coded status cells. Test records and trace matrices are formatted with appropriate column widths and styling.
Matrix Columns#
Test Records Matrix Columns#
Column |
Description |
|---|---|
Test Case |
Sequential test ID (TC001, TC002, etc.) or manual ID from |
Test Name |
pytest function name |
Outcome |
Test result: passed, failed, skipped, or error |
Requirements |
Item UIDs covered by this test |
Test Actions |
Steps performed (from |
Expected Results |
Acceptance criteria (from |
Actual Results |
Observed outcomes (from |
Notes |
Observations and failure messages (from |
Timestamp |
ISO 8601 UTC timestamp of test execution |
Parameterized Tests: When a test uses @pytest.mark.parametrize, each parameter variation receives a unique TC ID with an alphabetic suffix. For example, if test_boundary_values has three parameter sets, they become TC003a, TC003b, and TC003c. Suffixes follow the pattern: a-z, then aa, ab, etc. for tests with more than 26 parameters.
Trace Matrix Columns#
Column |
Description |
|---|---|
Traces To |
Ancestor UIDs (optional, enabled with |
[Document Columns] |
One column per document in hierarchy (e.g., UN, SYS, SRS), showing UID and requirement text |
Review Status |
Always present. Shows “Reviewed”, “Not Reviewed”, or “Suspect” based on the item’s review state |
[Extra Columns] |
Custom attribute columns configured via |
Tests |
pytest tests linked to leaf items, with TC IDs and outcomes |
Status |
Passed, Failed, Not Covered, Partial, or N/A |