Flow testing
Pipebase ships a built-in flow-test framework — a MUnit-class given/when/then surface for Camel flows, with connector mocking. It requires no separate test DSL beyond one YAML file per flow, and runs the same way locally, in the designer, and in CI.
What it is
Section titled “What it is”A flow test asserts against a real deployed flow running on a real Camel runtime — not a code-level unit test of a route builder, and not a fully mocked simulation. Under the hood:
- The flow-under-test deploys to a runtime (ephemeral, or one you point at).
- A test session opens on that runtime and arms one or more step
mocks — “when step
Xruns, short-circuit it and return this body / throw this exception” instead of letting the real connector fire. - The trigger fires (an HTTP request, or a message produced to a
direct:endpoint). - Assertions run against the HTTP response, specific steps’ captured in/out bodies, and how the mocked step(s) were called.
Because both the mock and the assertions ride the runtime’s real trace machinery, a green flow test is strong evidence the flow works end-to-end minus whatever you explicitly mocked — typically outbound connectors you don’t want to hit in CI, like an inventory API or a payment gateway.
The given/when/then model
Section titled “The given/when/then model”A suite is one YAML file with a list of tests. Each test has three parts:
version: 1tests: - id: t_reserve_ok name: reserves stock via the (mocked) inventory API given: mocks: - step: r0_s2 nodeId: r0_s2 respond: body: '{"reservationId":"R1"}' headers: Content-Type: application/json when: kind: http method: POST path: /orders body: SKU-123 headers: Content-Type: text/plain then: response: status: 200 bodyContains: R1 steps: - step: r0_s3 out: bodyContains: reserved SKU-123 mockCalled: - step: r0_s2 times: 1 withBodyContains: SKU-123 - id: t_inventory_down name: surfaces a 500 when the inventory connector fails given: mocks: - step: r0_s2 throw: type: java.io.IOException message: inventory down when: kind: http method: POST path: /orders body: SKU-9 headers: Content-Type: text/plain then: response: status: 500given.mocks[]arms step mocks before the trigger fires. Each mock targets a Camel step id and eitherresponds with a body/headers orthrows a configured exception.whenfires the trigger —kind: httpsends a real request to the flow’s HTTP trigger;kind: producesends to adirect:endpoint for flows triggered internally rather than over HTTP.thenasserts on the HTTPresponse, per-stepscaptured bodies, andmockCalled(did the mocked step get invoked, how many times, with what body). All body assertions supportbodyEquals,bodyContains,bodyJsonPath, andheaderEquals.
Authoring in the Tests drawer
Section titled “Authoring in the Tests drawer”The next-editor (/edit-next/:id) has a Tests drawer. It lets you add
a test, name it, pick the trigger kind, and mock/assert steps by pointing
at a node on the canvas rather than typing a raw Camel step id — a
dropdown lists every node with a stable step id, labelled by its display
name. Running the suite from the drawer shows pass/fail per test, and a
failing test highlights the involved nodes on the canvas in red so you can
jump straight from “test failed” to “here’s the responsible node.”
Saving in the drawer writes the canonical test store and re-exports a
human-readable flow.tests.yaml next to the flow’s Camel YAML — the format
shown above, meant for git and code review.
Running in CI
Section titled “Running in CI”pipebase-test --all --flows-dir <dir> --runtime ephemeral --junit out.xml| Flag | Meaning |
|---|---|
<flowId> (positional) | Run just this flow’s suite. |
--all | Run every flow under --flows-dir that has a test suite. |
--flows-dir <dir> | Data directory to scan. |
--runtime ephemeral | <url> | ephemeral spins up a throwaway container and tears it down afterward; a URL runs against an already-running runtime. |
--junit <path> | Write a JUnit XML report for CI test-result UIs. |
Exit code is non-zero if any suite has a failed test. A bundled
orders-api example ships under designer/examples/flow-tests/ and runs
in the project’s own CI leg on every push.
v1 limits
Section titled “v1 limits”- Trigger kinds: only
httpandproduce(direct:) triggers are supported today. Timer- or queue-triggered flows can’t be fired by a flow test yet. - One deploy per suite. All tests in a suite share a single deployment — if a test mutates state a later test depends on (an in-process cache, say), that state can bleed between tests. Order tests defensively.
matchis substring-only. Mock/assertion body matching has no regex or JSONPath wildcards beyond the explicitbodyJsonPathfield.- Only HTTP-transport runtimes are supported. Pipe-mode (tunnel)
runtimes don’t currently support test sessions — point
--runtimeat an inbound runtime URL or use the ephemeral local one.
Related
Section titled “Related”- API reference: Designer API — the
/api/flows/:id/tests*routes - API reference: Runtime API — the
/_api/test/*session endpoints - Flows — what a flow is