Skip to main content

Link sphinx-needs requirements (needs.json) to GoogleTest JUnit XML and emit an RTM report.

Project description

RTM – Requirements Traceability for Sphinx-Needs + GTest

RTM is a small, opinionated tool that links software requirements (from sphinx-needs) to unit tests (from GoogleTest JUnit XML), producing a clear, machine-readable requirements traceability matrix (RTM) and a human-readable summary.

It is designed to be:

  • Simple – no Sphinx plugins, no test framework hooks
  • Deterministic – all logic is explicit and inspectable
  • Extensible – users control how requirements are extracted from tests
  • CI-friendly – JSON output for downstream tooling

The CLI is the primary interface, but all components are importable as a Python module.


What this tool does

RTM answers questions like:

  • Which requirements have tests?
  • Which requirements are missing tests?
  • Which tests claim to cover requirements that don’t exist?
  • Which tests cover multiple requirements?
  • Are all tests for a given requirement passing?

It does not:

  • Enforce any particular testing style
  • Modify your test framework
  • Require Sphinx to know about tests
  • Require tests to be modeled as Sphinx needs

Inputs

1. Requirements (needs.json)

Generated by sphinx-needs when you build your documentation.

Example location:

docs/_build/needs/needs.json

Only needs of type req are considered.


2. Test results (JUnit XML)

Generated by GoogleTest, for example:

--gtest_output=xml:build/test-results/junit.xml

RTM reads:

  • suite name (classname)
  • test name (name)
  • status (pass, fail, error, skip)
  • optional <properties> blocks

Default behavior (very dumb, by design)

By default, RTM assumes:

The test name itself is the requirement ID.

Example:

TEST(MathUtilsTest, REQ_MATH_ADD_001)

If your test names include extra text:

REQ_MATH_ADD_001_AddPositiveNumbers

…the default extractor will not match this. This is intentional.

The philosophy is:

  • Start with a trivial, predictable default
  • Let users explicitly define smarter extraction logic

Custom requirement extraction (the key feature)

Instead of hard-coding regex rules, RTM lets you define how requirements are extracted from each test.

You provide a small Python function that receives:

(suite: str, name: str, properties: dict[str, list[str]])

…and returns:

list[str]  # requirement IDs

RTM then:

  • Validates extracted IDs against needs.json
  • Links known IDs
  • Reports unknown / missing / unmapped cases separately

Example: properties-first extractor (recommended)

If your JUnit XML includes properties like:

<property name="requirement" value="REQ_MATH_ADD_001"/>

Create a file extractor_props_first.py:

def extract_requirements(suite, name, properties):
    # Prefer explicit metadata
    vals = properties.get("requirement")
    if vals:
        return vals

    # Fallback (optional)
    return []

Run RTM with:

rtm-link \
  --needs docs/_build/needs/needs.json \
  --junit build/test-results/junit.xml \
  --out rtm_report.json \
  --extractor extractor_props_first.py \
  --print

This is the cleanest long-term approach:

  • No regex
  • No naming conventions
  • Stable under renames

CLI usage

rtm-link \
  --needs PATH/TO/needs.json \
  --junit PATH/TO/junit.xml \
  --out PATH/TO/rtm_report.json \
  [--extractor extractor.py] \
  [--print]

Options:

  • --needs – sphinx-needs needs.json
  • --junit – JUnit XML from gtest
  • --out – output JSON report
  • --extractor – custom Python extractor module
  • --print – print human-readable report to stdout

Output

Human-readable summary

Printed with --print, e.g.:

=== RTM Link Summary ===
Requirements: 3
  With >=1 test: 3
  Missing tests: 0
  All tests passing: 3
  Any test failing: 0
Tests: 3
  Unmapped tests (no IDs extracted): 0
  Multi-mapped tests: 0
  Tests w/ unknown req IDs: 0
  Tests w/ only unknown IDs: 0
  Unknown req IDs (unique): 0

JSON report

Written to --out, suitable for CI, dashboards, or custom checks.

Includes:

  • Summary counts
  • Per-requirement test linkage
  • Unmapped tests
  • Multi-mapped tests
  • Unknown requirement references
  • Missing / failing requirements

Semantics (important)

RTM distinguishes these cases explicitly:

  • Unmapped test
    Extractor returned no IDs at all.

  • Unknown requirement reference
    Extractor returned IDs that do not exist in needs.json.

  • Only unknown requirements
    Extractor returned IDs, but none were valid.

These are intentionally separate failure modes.


Using RTM as a Python module

RTM is fully importable; the CLI is just a thin wrapper.

Example:

from pathlib import Path
from rtm_needs import NeedsJsonReader, JUnitReader, Linker

reqs = NeedsJsonReader().read(Path("docs/_build/needs/needs.json"))
tests = JUnitReader().read(Path("build/test-results/junit.xml"))

report = Linker().link(reqs=reqs, tests=tests)
print(report)

With a custom extractor:

def extract_requirements(suite, name, properties):
    return properties.get("requirement", [])

report = Linker().link(reqs=reqs, tests=tests, extractor=extract_requirements)

What RTM is not (by design)

  • Not a requirements management system
  • Not a test framework
  • Not a Sphinx extension
  • Not a policy engine

RTM is a bridge between two existing artifacts:

  • Requirements written for humans
  • Tests written for machines

Roadmap (non-binding)

Possible future additions:

  • Optional CI failure policies
  • Built-in extractors (name prefix, delimiters, etc.)
  • Coverage percentages / thresholds
  • Alternate output formats (Markdown, CSV)
  • Small test suite

All intentionally deferred until real usage demands them.


License

MIT (or your preferred OSS license).


Philosophy

Traceability should be explicit, inspectable, and boring.

If it’s surprising, it’s wrong.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rtm_needs-0.2.0.tar.gz (13.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rtm_needs-0.2.0-py3-none-any.whl (15.0 kB view details)

Uploaded Python 3

File details

Details for the file rtm_needs-0.2.0.tar.gz.

File metadata

  • Download URL: rtm_needs-0.2.0.tar.gz
  • Upload date:
  • Size: 13.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for rtm_needs-0.2.0.tar.gz
Algorithm Hash digest
SHA256 1c146ee16a81c1be158a7747b476f0c413886e3a0046682c902de9de37883a07
MD5 52e975fb942ff4c89ed3d7808b893afd
BLAKE2b-256 0b4e9035202830bf93fadd6f23544a435127fb0577773617b11540d37d4ce0d8

See more details on using hashes here.

File details

Details for the file rtm_needs-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: rtm_needs-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 15.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for rtm_needs-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1de280f8194d5c142e164dd01582e4caeecbd89d9e420822eeddb7d5ceec4f8d
MD5 fecb3bd7d8795d2d626ce6e15a230def
BLAKE2b-256 ba72ea0257c92b12cfe7cff26882d1572654b0d9b3be66d7f3360132282a4545

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page