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.1.0.tar.gz (12.1 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.1.0-py3-none-any.whl (13.0 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for rtm_needs-0.1.0.tar.gz
Algorithm Hash digest
SHA256 6db80a592fe587a40dc1c7d753b2e3ac259812a7854af07dd62e706a2b102b29
MD5 61a80c113af3aa472eb17ac9f716ce86
BLAKE2b-256 5e319ea785d110cf973818bb31e226774ff8b186a87850666640f50abd6b2c6d

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for rtm_needs-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 faf22372472278c0cda4c415faf7153b13e15a861c5be86a48894778ae77ae92
MD5 e8e1104673f8c05920737b70a50c3e26
BLAKE2b-256 4c87014781848a53244178853762dee8876deb1657f5d4d88e4b7b29cc64026f

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