Decorators
The four decorators inroboticks are the SDK’s smallest surface and the one users touch most. All four work on any callable that pytest collects — functions, methods, parametrized variants, async tests. They stack in any order.
@confirms(*req_ids)
Records which requirement IDs the decorated test confirms. The pytest plugin reads this and emits a <property name="roboticks.confirms" value="REQ-001,REQ-014"/> into the JUnit XML at session-end.
Signature
| Parameter | Type | Constraint |
|---|---|---|
req_ids | *str | At least one. Must match a known requirement ID after platform ingestion, otherwise the platform reports the test as “confirms an unknown requirement” in the Check Run. |
Behaviour
- Stacking —
@confirms("A")on a class plus@confirms("B")on a method unions to{"A", "B"}. Useful when an entire test class addresses one umbrella requirement and individual methods address sub-requirements. - Parametrize — A
@pytest.mark.parametrizevariant inherits the function’s@confirmsset; all branches confirm the same requirement IDs. If you need different requirements per branch, split into multiple test functions. - Skipped tests — A skipped test still records its
@confirms(so the matrix shows which requirements are intended to be covered, even when the test didn’t run on this commit). The matrix surfaces them with a “skipped” badge.
Example
@tags(*tags)
Free-form labels for filtering. The platform doesn’t interpret them — they are pass-through metadata for your filters, dashboards, and policies.
Signature
Conventions
By community convention (not enforced):| Tag | Meaning |
|---|---|
smoke | Run on every PR |
nightly | Run only on the nightly suite |
slow | Wall-clock > 10 s |
safety | Touches a safety requirement |
flaky | Known intermittent; quarantine candidate |
Example
@deadline(milliseconds=int)
Fails the test if its wall-clock duration exceeds the budget. Useful for soft real-time guarantees that don’t otherwise show up as an assertion.
Signature
| Parameter | Type | Constraint |
|---|---|---|
milliseconds | int (keyword-only) | > 0 |
Behaviour
- The decorator wraps the test body in a
time.monotonic()measurement and raisesDeadlineExceeded(anAssertionErrorsubclass) if the test runs over. - Reported in JUnit XML as
<property name="roboticks.deadline_ms" value="100"/>. - The platform surfaces the actual duration vs the deadline in the run detail. A test that passes its assertions but blows the deadline is failed.
Example
Interaction with pytest timeouts
@deadline and pytest-timeout are independent. pytest-timeout kills the process; @deadline only fails the test. Use both for hard-stop budgets:
@requires_sim(engine, *, gpu=False)
Tells the job router the test needs a simulation runtime.
Signature
| Parameter | Type | Constraint |
|---|---|---|
engine | Literal["gazebo", "webots"] | Required. |
gpu | bool (keyword-only) | Defaults to False. |
Behaviour
- Reported in JUnit XML as
<property name="roboticks.requires_sim" value="gazebo:gpu"/>or"gazebo"ifgpu=False. - The platform’s scheduler refuses to dispatch the test to a runner that doesn’t satisfy the engine + GPU label.
- Local pytest runs do not skip the test — they run it. If sim isn’t available locally the test will fail at the rclpy step, which is the right behaviour: a developer needs to know they’re trying to run a sim test without a sim.
Example
Stacking order
Decorators are evaluated bottom-up (closest-to-function first), but for these four the order doesn’t change behaviour — they are independent metadata. Pick a convention and stick with it. The convention in our examples:What about @pytest.mark.X?
Roboticks decorators are not pytest markers. They mutate the function’s attributes; the pytest plugin reads those attributes at collection time. This avoids pytest’s marker-registration warnings and keeps @confirms working on classes (where @pytest.mark.X semantics are subtle).
You can still use pytest markers freely. They land in the JUnit XML as standard pytest properties; they don’t conflict with the roboticks.* namespace.
Next
Pytest plugin
How the plugin reads these decorators and writes JUnit properties.
Assertions
The rclpy-aware companion APIs.
Sim runners
What
@requires_sim triggers on the runner side.Wire contract
The JUnit-with-confirms schema these decorators feed into.