Documentation Index
Fetch the complete documentation index at: https://docs.ntropii.com/llms.txt
Use this file to discover all available pages before exploring further.
ntro.testing is the inner-loop test harness for runbook authors. It boots an in-memory Temporal (temporalio.testing.WorkflowEnvironment), registers your workflow plus any child workflows with auto-mocked activities, and drives the agent loop per scenario.
The whole thing runs sub-second. No Temporal cluster, no Docker, no deploy cycle. Catches the same workflow bugs the deployed e2e flow would, but in seconds.
Install
[testing] extra adds the harness on top of [workflow]. The ntro workflow test CLI command installs this transitively.
The API
load_runbook(path)— discover the workflow class, activities, and skill definition under a runbook directoryWorkflowHarness(workflow, child_workflows=[...])— async context manager that boots the in-memory Temporal envScenario(name, ...)— scripts the HITL responses and per-step overrides for a single test run
Canonical example
Lifted fromnav-monthly/tests/test_scenarios.py:
What’s auto-mocked
The harness fakes the things that would otherwise need a real environment:Activity returns
Activity returns
Derived from each
Fields with defaults are left alone — the runbook author’s defaults are usually the most realistic value the harness can produce, so it doesn’t override them.
@activity.defn’s return type via Pydantic introspection. Required fields get type-conformant fakes:| Type | Fake |
|---|---|
str | "auto-mock" |
int, float, Decimal | 0 |
bool | False |
datetime, date | now() / today() |
BaseModel (nested) | recursive fake |
HITL responses
HITL responses
Controlled by the
Scenario. HAPPY approves every review, REJECT_ALL rejects every review. For mixed cases:submit_file signals
submit_file signals
The harness sends a fake
document_ref plus tenant_slug / entity_slug derived from the workflow’s advertised args. Your runbook’s parse_pdf / parse_starting_tb activities receive a real-shaped payload without anything having to actually upload a file.Built-in scenarios
| Name | Behaviour |
|---|---|
HAPPY | Auto-approves every review; uses fakes for everything else. The path that exercises the most code. |
REJECT_ALL | Auto-rejects every review. Verifies your runbook handles rejection cleanly — workflows should terminate without dangling state. |
from ntro.testing import HAPPY, REJECT_ALL).
Custom scenarios
for scenario in [...] loop. Run a custom scenario when you want to verify a specific edge case (a rejection followed by a re-submit, a correction that shifts the GL allocation, etc.).
Why this exists
The deployed flow boots Temporal, spawns a worker, registers workflows, listens for signals, processes activities — for a runbook author iterating on a small change, that’s seconds-to-minutes per cycle. The harness skips all of it. You change a line inactivities.py, ntro workflow test runs, you see the result. Inner loop is tight enough that runbook authors actually use it.
The harness uses the same code paths your runbook will use in production (Temporal’s in-memory environment, real ntro.workflow machinery, real Pydantic models). It’s not a separate test runtime — it’s the same runtime, just spun up fast.
Related
Testing locally (CLI)
ntro workflow test wraps everything on this page in a CLI.Deploy to production
Once your scenarios pass locally, deploy.