mcpField
C
camunda-process-test

camunda-process-test

github.com/camundaTesting & quality26123 installsUpdated 1d ago
Repository

About camunda-process-test

camunda-process-test is a testing skill for Camunda 8.8+ processes, aimed at developers using Maven and Java. It plans test segments for BPMN element and routing coverage, then checks gaps with coverage reports.

Key features

  1. 01Plan a minimal set of BPMN coverage segments
  2. 02Author instruction-based or Java tests
  3. 03Run Maven tests
  4. 04Check element and sequence-flow coverage
  5. 05Find redundant scenarios and coverage gaps

Use cases

  1. 01Verify BPMN gateway routing
  2. 02Cover DMN rules and boundary events
  3. 03Add missing process test scenarios
  4. 04Use coverage reports to locate uncovered elements

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/camunda/skills --skill camunda-process-test

After installing, type/camunda-process-testin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

portability.json
references/
authoring.md
ci.md
connectors-runtime.md
coverage-strategy.md
evaluation.md
run-and-diagnose.md
setup.md
test-context.md
troubleshooting.md

Details

From the project README

Camunda Process Test

WORKFLOW SKILL: plan segments, author scenarios, run the Maven test command, and close coverage gaps.

DO NOT USE FOR:

Do not use this skill to author BPMN, DMN, FEEL, or forms, deploy to a live cluster, or test UI behavior. Route those tasks to camunda-bpmn, camunda-dmn, camunda-feel, camunda-forms, camunda-process-mgmt, or the relevant UI test framework.

Author and run Camunda Process Test suites for Camunda 8.8+ that reach 100% BPMN element coverage with the minimum number of test segments. Test assertions are limited to reachability and routing — CPT exercises that the engine traverses the right elements, not the data values produced by service tasks or external systems.

Prerequisites

  • Java 21+, Maven (or ./mvnw), Docker runtime (OrbStack, Docker Desktop, or Rancher Desktop) — see references/setup.md
  • camunda-process-test-spring 8.8+ on the test classpath for Java fallback suites; the instruction-based .test.json format and 8.9-only APIs require 8.9+
  • A working BPMN file (lint clean — see camunda-bpmn). DMN and form files referenced by the BPMN must also be present.

For a Node.js layout, set NODE_RESOURCE_DIR and run Maven from the generated test/ directory as described in references/setup.md. The Maven commands below are shell-neutral; the Node.js POM reads the environment variable and standard Java layouts do not need it.

Cross-References

  • camunda-bpmn: Run c8ctl bpmn lint on the process under test before authoring scenarios — failing lints surface as deploy-time @TestDeployment failures.
  • camunda-feel: Use when a gateway condition or DMN entry is unclear; FEEL semantics drive which segment hits which branch.
  • camunda-dmn: Use when a DMN decision is the unit under test — CPT exercises it via the calling business rule task; pair with npx dmnlint for structural checks.
  • camunda-job-workers: Use when the handler code that backs a service task is itself under test — CPT drives BPMN reachability; worker unit tests drive handler behaviour.
  • camunda-connectors-development: Use when a custom connector is the unit under test — CPT exercises it from the BPMN side; SDK-side tests cover the connector class directly.
  • camunda-ai-agents: Use when testing an AI Agent Sub-process — drives the BPMN shape that COMPLETE_JOB_AD_HOC_SUB_PROCESS and context.when().then() orchestrate.
  • camunda-process-mgmt: CPT runs against an embedded Zeebe engine — it does not use the c8ctl-managed cluster or any profile. No c8ctl call deploys a process under test.

Scope boundaries

  • In scope: BPMN reachability (every element visited at least once), gateway-branch selection, DMN rule selection, error-boundary firing, timer / escalation boundary firing, end-event selection.
  • Out of scope: asserting data values produced by service tasks, external system payloads, UI behavior, agent / LLM output. Do not write ASSERT_VARIABLE instructions on service-task output unless the variable is the FEEL input to a downstream gateway you also test.

Workflow

1. Detect

Find the BPMN under test in priority order:

  1. src/main/resources/processes/
  2. src/main/resources/bpmn/
  3. The resource directory declared by the project build (for example, a Node.js project may keep it at resources/ while the test harness lives in test/).

Skip target/, node_modules/, .git/, build/. If multiple files match, list them and ask which to target.

Check pom.xml (or test/pom.xml) for camunda-process-test-spring. If missing, go to step 2.

If scenarios already exist, run a drift check before editing tests:

git diff <base-branch>...HEAD -- <bpmn-path>

Use the PR base branch or repository default branch as <base-branch> (often main).

Then classify current suite gaps:

  • Broken: scenario references an elementId or processDefinitionId that no longer exists.
  • Stale: IDs still exist, but branch-driving variables or assumptions no longer match gateway/DMN behavior.
  • Missing: new branches, boundary events, or end events have no segment coverage.

Fix in this order: broken → stale → missing, then run mvn test and continue with coverage verification.

2. Setup (only if missing)

Follow references/setup.md: run the readiness preflight (Java, Maven/wrapper, Docker), add the CPT dependency, scaffold src/test/java/io/camunda/tests/ProcessTest.java and src/test/resources/scenarios/ for CPT 8.9+, or use the Java fallback for CPT 8.8. Confirm with mvn test-compile.

3. Plan segments (set-cover, not per-element)

Plan the minimum number of segments before authoring anything. Apply references/coverage-strategy.md:

  1. Parse the BPMN: processId, element IDs and types, gateway outgoing flows + conditions, error / timer / escalation boundaries, end events, called DMN decisions (<zeebe:calledDecision decisionId="…">) and the DMN rules inside them.
  2. Enumerate candidate segments. For every gateway branch, DMN rule, boundary event, and alternate end event, define one minimal candidate segment rooted at the nearest upstream decision point. For each candidate, statically predict its full visited-element + sequence-flow set by walking the BPMN forward from the root through the targeted branch to the next rejoin or end event.
  3. Greedy set-cover. Repeatedly pick the candidate whose predicted set covers the largest number of still-uncovered ids. Tie-break by shortest path (cheapest to author). Stop when the union covers every id.
  4. Diagnostic-isolation override (optional). If two chosen segments share a root but exercise different failure modes (e.g. one fires a boundary event, the other completes the user task normally), keep both so a failure points at one cause cleanly. Apply only when the user is debugging a specific area; default is pure set-cover.
  5. Print the segment plan as a table: segment name | root | predicted ids covered | end condition. Authoring then implements exactly this list — no speculative scenarios that may be deduped later.

Example: for a gateway with approved and rejected flows, plan one segment per flow, predict the visited IDs through the next join, and keep the smallest set of segments that covers both branches and the shared end path.

4. Author

For CPT 8.9+, write one entry inside src/test/resources/scenarios/<processId>.test.json using references/authoring.md. For CPT 8.8, use the Java fallback described in that reference instead of .test.json. Naming: "<who/what> — <outcome>". Assertions: ASSERT_ELEMENT_INSTANCES on the elements the segment must visit, ASSERT_PROCESS_INSTANCE only when the segment runs to an end event.

For CPT 8.9+, use the Java fallback only when the segment needs Spring bean mocking, parameterized data tables, non-deterministic runtime races (context.when().then() (8.9+)), or assertions richer than the JSON instruction set offers. For CPT 8.8, Java tests are required because the instruction-based format is not available. See references/test-context.md; Java tests are invisible to Web Modeler.

5. Run

Run Maven from the directory containing the relevant pom.xml. For a Node.js layout, use the generated test/ directory and keep NODE_RESOURCE_DIR set to the resolved resource directory for this command and every retry, as described in references/setup.md.

mvn test

On failure, diagnose with references/troubleshooting.md. Distinguish test problems (variable typo, wrong element id, missing instruction) from process problems (wrong FEEL condition, wrong DMN rule, wrong error code). Fix the right side. Re-run. Stop after 3 repair cycles with no progress.

When the run exits — pass or fail — proceed straight to step 6 and open the coverage report.

6. Coverage check — exit gate (100% loop)

CPT emits a coverage report at target/coverage-report/report.html (per-process HTML; the page embeds the full coverage dataset in a window.COVERAGE_DATA JSON literal). Parse it:

python3 - <<'PY'
import re, json
html = open("target/coverage-report/report.html").read()
# Balanced-brace extraction. Walk character by character, but track string
# state so braces inside JSON strings (e.g. inside a description) don't
# unbalance the counter.
m = re.search(r"window\.COVERAGE_DATA\s*=\s*", html)
start = html.index("{", m.end())
depth = 0; in_str = False; esc = False; end = start
for k, ch in enumerate(html[start:], start):
    if in_str:
        if esc: esc = False
        elif ch == "\\": esc = True
        elif ch == '"': in_str = False
    else:
        if ch == '"': in_str = True
        elif ch == "{": depth += 1
        elif ch == "}":
            depth -= 1
            if depth == 0:
                end = k + 1
                break
data = json.loads(html[start:end])
el = set(); flows = set(); total = None
for s in data["suites"]:
    for r in s["runs"]:
        for c in r["coverages"]:
            el.update(c.get("completedElements", []))
            flows.update(c.get("takenSequenceFlows", []))
            total = c.get("totalElementCount", total)
covered = len(el) + len(flows)
print(f"coverage={covered}/{total}={100*covered/total:.2f}%")
print("covered_elements:", sorted(el))
print("covered_flows:", sorted(flows))
PY

Diff against the BPMN element + sequenceFlow id list (grep -oE 'id="[A-Za-z0-9_]+"' <bpmn>, exclude _di, BPMNDiagram, BPMNPlane, Definitions_, ErrorDef_, TimerDef_, Signal_, Message_).

Surface the HTML report path to the user as soon as mvn test exits — pass or fail. The agent already verifies coverage from the JSON data above; the HTML report is for the user to inspect. Print the absolute path (target/coverage-report/report.html) in the final reply so they can open it themselves. In an interactive local session you may additionally offer to open it on their behalf (open on macOS, xdg-open on Linux, start on Windows) — do not run that unprompted in a sandboxed / remote environment where it has no effect.

Patch-loop on prediction misses — default behavior. Set-cover planning in step 3 should reach 100% on the first authoring pass. When it does not, the gap is a prediction miss: the static walk for some candidate did not match runtime behavior. For each uncovered id:

  1. Classify the miss: element (visit it directly), or sequence flow (its source must be hit and the condition routing through it must be satisfied — usually a gateway branch the planner failed to attribute).
  2. Re-run greedy set-cover restricted to the remaining uncovered ids. Add the chosen candidates (often one) to the scenario file.
  3. For timer boundary events: use INCREASE_TIME with an ISO 8601 duration greater than the timer cycle (e.g. "PT25H" for R/PT24H). The boundary fires; the outgoing path's job is created; complete it with COMPLETE_JOB.
  4. For message boundary events: PUBLISH_MESSAGE instruction with matching name + correlationKey.
  5. Re-run step 5 (mvn test) → step 6. Each iteration should strictly reduce the uncovered set; if it does not, the planner's path prediction is wrong — fix the prediction logic in references/coverage-strategy.md, do not paper over with more scenarios.

Hard blockers that terminate the loop:

  • Same set of ids uncovered after 2 consecutive iterations — surface the list and stop.
  • An uncovered element is dead code (no inbound flow, or its inbound condition is unsatisfiable) — flag as a BPMN defect, point at camunda-bpmn, stop.
  • Test infrastructure failure repeats (Docker down, deploy parse error) — stop and route to references/troubleshooting.md.

Do not declare the suite done while ids remain uncovered and no hard blocker applies.

Note: in early 8.9 SNAPSHOT releases the report generator may throw IllegalStateException: Report resources not found and skip the HTML output. Tests still pass. Walk the BPMN against scenarios from source to confirm coverage in that case.

7. Verify no redundancy slipped through

Set-cover planning in step 3 should produce a non-redundant suite by construction. Verify with a leave-one-out check against the runtime coverage data: for each scenario, compute the union of all other scenarios' covered ids; if removing the scenario loses zero ids, it is redundant and the planner has a bug — fix the planner, then drop the scenario.

Also flag (cheap, do unconditionally):

  • Scenario names that do not match <who/what> — <outcome> (e.g. "test1", "happy").
  • Duplicated descriptions across scenarios.
  • ASSERT_VARIABLE instructions on variables that no gateway or DMN downstream consumes — data assertions are out of scope.
8. Report

Print the Surefire result line, the coverage percentage, the segment count, and any flagged duplicates.

Tests run: 6, Failures: 0, Errors: 0, Skipped: 0
Coverage: 100% (24/24 elements)
Segments: 1 happy path + 5 secondary
Duplicates flagged: 0

Maintenance workflows for existing suites

When tests already exist and the user asks to run, diagnose, or improve them (without generating a brand-new suite), use these focused workflows:

  1. Run and diagnose failures — execute mvn test from the directory containing the relevant pom.xml; for a Node.js layout, run it from test/ with NODE_RESOURCE_DIR set to the resolved resource directory for the initial run and every retry. Classify each failure as infrastructure/test/process, then fix in batches. Use references/troubleshooting.md plus references/run-and-diagnose.md.
  2. Evaluate coverage gaps before writing new tests — explain current suite coverage in business terms, list uncovered branches/boundaries/rules, and recommend the smallest next set of scenarios. See references/evaluation.md.
  3. Wire tests into CI — configure CI to run CPT reliably and publish JUnit artifacts, with optional integration profile runs gated to trusted branches. See references/ci.md.

These workflows are complementary: evaluate gaps first, implement new scenarios, then run/diagnose locally and in CI.

References

  • setup.md — Java, Maven, Docker prereqs; CPT dependency; test scaffold layout; Spring Boot 4.x pin
  • coverage-strategy.md — segment selection rules per BPMN element type, including ad-hoc subprocess tool activation
  • authoring.md — .test.json schema, full 8.9 instruction reference, Java fallback
  • test-context.md — CamundaProcessTestContext Java API surface (job/decision/child-process mocking, time control, conditional behavior)
  • connectors-runtime.md — enabling the Connectors runtime alongside Zeebe; WireMock pattern; inbound webhooks
  • troubleshooting.md — failure diagnosis table (test problem vs. process problem)
  • run-and-diagnose.md — test-run execution loop and failure-batch repair strategy
  • evaluation.md — coverage-gap assessment and recommendation workflow
  • ci.md — CI pipeline patterns for CPT execution and test-report publishing

Comments

Markdown supported