Migrate to Camunda Process Test
Camunda Process Test (CPT) is a library to test your BPMN processes and your process applications. It is the successor to Zeebe Process Test (ZPT).
Starting with version 8.8, ZPT is deprecated and will be removed in version 8.10.
See the announcement for details.
This guide walks you through migrating your existing test cases from ZPT to CPT step-by-step.
Be aware that there are differences between ZPT and CPT in both API and behavior, which may increase migration effort depending on your existing test cases.
Key differences:
- Underlying engine: ZPT uses only Camunda’s workflow engine (Zeebe) with access to internal components, whereas CPT runs the full Camunda distribution and interacts with the Orchestration Cluster API.
- Assertions and utilities: CPT uses different names to align with the API, and not all ZPT assertions/utilities have equivalents in CPT.
- Startup time: CPT takes longer to start as it runs the full Orchestration Cluster distribution.
Key advantages of CPT:
- Access to Camunda’s Orchestration Cluster API and Connectors
- Support for Camunda user tasks
- Blocking assertions for asynchronous processing
- Enhanced mocking utilities
Update your dependency
First, update your Maven dependency.
-
If you use ZPT with Camunda Spring Boot SDK integration
(artifactId: spring-boot-starter-camunda-test
orspring-boot-starter-camunda-test-testcontainer
),
replace it with CPT’s Spring integration module. -
If you use ZPT without Spring
(artifactId: zeebe-process-test-extension
orzeebe-process-test-extension-testcontainer
),
replace it with CPT’s Java module.
- Camunda Spring Boot SDK
- Java client
In your Maven pom.xml
, add the dependency:
<dependency>
<groupId>io.camunda</groupId>
<artifactId>camunda-process-test-spring</artifactId>
<scope>test</scope>
</dependency>
In your Maven pom.xml
, add the dependency:
<dependency>
<groupId>io.camunda</groupId>
<artifactId>camunda-process-test-java</artifactId>
<scope>test</scope>
</dependency>
Choose your runtime
Next, choose how you want to run CPT, considering your environment. CPT can be used in two modes:
- CPT with Testcontainers (as equivalent to ZPT with Testcontainers)
- CPT with remote engine (as equivalent to ZPT's embedded runtime)
ZPT with Testcontainers
If you use ZPT with Testcontainers (
artifactId: zeebe-process-test-extension-testcontainer/spring-boot-starter-camunda-test-testcontainer
), then you can
use CPT's default Testcontainers runtime without
additional changes. Check the documentation on how to use CPT with Testcontainers here
ZPT's embedded runtime
If you use ZPT’s embedded runtime
(artifactId: zeebe-process-test-extension
or spring-boot-starter-camunda-test
),
switch to CPT’s remote runtime.
Choose this option only if you cannot install a Docker-API compatible container runtime (e.g., Docker on Linux or Docker Desktop).
In this mode, CPT connects to a remote runtime, such as a local Camunda 8 Run running on your machine. Prepare your remote runtime:
-
Install Camunda 8 Run
Follow the installation guide on your machine. -
Enable the management clock endpoint
See prerequisites:- Create an
application.yaml
file in the root/c8run
directory. - Add:
zeebe.clock.controlled: true
- Create an
-
Start Camunda 8 Run.
-
Switch CPT’s runtime mode to
remote
in your project configuration.
- Camunda Spring Boot SDK
- Java client
In your application.yml
(or application.properties
):
camunda:
process-test:
runtime-mode: remote
In your /camunda-container-runtime.properties
file:
runtimeMode=remote
Migrate your process tests
Now, it's time to migrate your process tests.
- Camunda Spring Boot SDK
- Java client
First, migrate the general test class structure:
-
Replace annotations and types
- Replace
@ZeebeSpringTest
with@CamundaSpringProcessTest
- Replace the type
ZeebeTestEngine
withCamundaProcessTestContext
- Replace
-
Remove record stream fields
CPT does not provide direct access to records. Instead, use the SDK to request data from the API.
Below is an example of a ZPT test class:
import io.camunda.zeebe.process.test.extension.testcontainer.ZeebeProcessTest;
@SpringBootTest
@ZeebeSpringTest
class MyProcessTest {
@Autowired private CamundaClient client;
@Autowired private ZeebeTestEngine engine;
@Autowired private RecordStream recordStream;
@Test
void shouldCompleteProcess() {
// given
final ProcessInstanceEvent processInstance = client
.newCreateInstanceCommand()
.bpmnProcessId("my-process")
.latestVersion()
.send()
.join();
// when: drive the process forward
// then
BpmnAssert.assertThat(processInstance)
.hasPassedElementsInOrder("start", "task1", "task2", "task3", "end")
.isCompleted();
}
}
First, migrate the general test class structure:
- Replace the annotation
@ZeebeProcessTest
with@CamundaProcessTest
. - Replace the type
ZeebeTestEngine
withCamundaProcessTestContext
. - Remove the field for
RecordStream
. CPT does not provide direct access to records; instead, use the SDK to request data from the API.
Below is an example of a ZPT test class:
import io.camunda.zeebe.process.test.extension.testcontainer.ZeebeProcessTest;
@ZeebeProcessTest
class MyProcessTest {
private CamundaClient client;
private ZeebeTestEngine engine;
private RecordStream recordStream;
@Test
void shouldCompleteProcess() {
// given: the processes are deployed
final ProcessInstanceEvent processInstance = client
.newCreateInstanceCommand()
.bpmnProcessId("my-process")
.latestVersion()
.send()
.join();
// when: drive the process forward
// then
BpmnAssert.assertThat(processInstance)
.hasPassedElementsInOrder("start", "task1", "task2", "task3", "end")
.isCompleted();
}
}
This is the equivalent CPT test class:
- Camunda Spring Boot SDK
- Java client
import io.camunda.process.test.api.CamundaAssert;
import io.camunda.process.test.api.CamundaProcessTestContext;
import io.camunda.process.test.api.CamundaSpringProcessTest;
@SpringBootTest
@CamundaSpringProcessTest
class MyProcessTest {
@Autowired private CamundaClient client;
@Autowired private CamundaProcessTestContext processTestContext;
@Test
void shouldCompleteProcess() {
// given
final ProcessInstanceEvent processInstance = client
.newCreateInstanceCommand()
.bpmnProcessId("my-process")
.latestVersion()
.send()
.join();
// when: drive the process forward
// then
CamundaAssert.assertThat(processInstance)
.hasCompletedElementsInOrder("start", "task1", "task2", "task3", "end")
.isCompleted();
}
}
import io.camunda.process.test.api.CamundaAssert;
import io.camunda.process.test.api.CamundaProcessTest;
import io.camunda.process.test.api.CamundaProcessTestContext;
@CamundaProcessTest
class MyProcessTest {
private CamundaClient client;
private CamundaProcessTestContext processTestContext;
@Test
void shouldCompleteProcess() {
// given: the processes are deployed
final ProcessInstanceEvent processInstance = client
.newCreateInstanceCommand()
.bpmnProcessId("my-process")
.latestVersion()
.send()
.join();
// when: drive the process forward
// then
CamundaAssert.assertThat(processInstance)
.hasCompletedElementsInOrder("start", "task1", "task2", "task3", "end")
.isCompleted();
}
}
Then, review all test methods and migrate the assertions and utilities. See the following sections for detailed instructions.
Process instance assertions
ZPT has assertions for a process instance using BpmnAssert.assertThat()
with the ProcessInstanceEvent
or the
ProcessInstanceResult
.
CPT has equivalent assertions using CamundaAssert.assertThat()
.
// given
ProcessInstanceEvent processInstance = //
// ZPT:
BpmnAssert.assertThat(processInstance).isCompleted();
// CPT:
CamundaAssert.assertThat(processInstance).isCompleted();
Some of CPT's assertions have different method names or signatures. Check the following list for the equivalent CPT assertion:
ZPT: BpmnAssert.assertThat(processInstance) | CPT: CamundaAssert.assertThat(processInstance) |
---|---|
isStarted() | isCreated() |
isActive() | isActive() |
isCompleted() | isCompleted() |
isNotCompleted() | Not supported Instead, use isActive() or isTerminated(). |
isTerminated() | isTerminated() |
isNotTerminated() | Not supported Instead, use isActive() or isCompleted(). |
isWaitingAtElements() | hasActiveElements() |
isWaitingExactlyAtElements() | hasActiveElementsExactly() |
isNotWaitingAtElements() | hasNoActiveElements() |
hasPassedElement() | hasCompletedElement() |
hasPassedElementsInOrder() | hasCompletedElementsInOrder() |
hasNotPassedElement() | hasNotActivatedElements() |
hasVariable() | hasVariableNames() |
hasVariableWithValue() | hasVariable() |
hasAnyIncidents() | hasActiveIncidents() |
hasNoIncidents() | hasNoActiveIncidents() |
isWaitingForMessages() | Coming soon with 8.8 |
isNotWaitingForMessages() | Coming soon with 8.8 |
hasCorrelatedMessageByName() | Coming soon with 8.8 |
hasCorrelatedMessageByCorrelationKey() | Coming soon with 8.8 |
hasCalledProcess() | Not supported Instead, use a ProcessInstanceSelector to assert the child process instance. |
hasNotCalledProcess() | Not supported Instead, assert the call activity or the child process instance. |
Deployment assertions
ZPT has assertions for a deployment using BpmnAssert.assertThat()
with the DeploymentEvent
.
CPT has no equivalent assertions. Instead, you could write a custom assertion with AssertJ to verify the properties of the deployment event.
// given
DeploymentEvent deploymentEvent = //
// ZPT:
BpmnAssert.assertThat(deploymentEvent).containsProcessesByResourceName("my-process.bpmn");
// CPT:
Assertions.assertThat(deploymentEvent.getProcesses())
.extracting(Process::getResourceName)
.contains("my-process.bpmn");
Job assertions
ZPT has assertions for an activated job using BpmnAssert.assertThat()
with the ActivatedJob
.
CPT has no equivalent assertions. Instead, you could write a custom assertion with AssertJ to verify the properties of the activated job.
// given
ActivatedJob activatedJob = //
// ZPT:
BpmnAssert.assertThat(activatedJob).hasElementId("elementId");
// CPT:
Assertions.assertThat(activatedJob.getElementId()).isEqualTo("elementId");
Message assertions
ZPT has assertions for a published message using BpmnAssert.assertThat()
with the PublishMessageResponse
.
CPT has no equivalent assertions. Instead, you could use a ProcessInstanceSelector to find the correlated process instance, or use the correlate message API that returns the process instance key.
// ZPT:
final PublishMessageResponse publishMessageResponse = //
BpmnAssert.assertThat(publishMessageResponse)
.hasCreatedProcessInstance()
.extractingProcessInstance()
.isCompleted();
// CPT:
final CorrelateMessageResponse correlateMessageResponse = //
// The correlate command would fail if the message could not be correlated
CamundaAssert.assertThatProcessInstance(byKey(correlateMessageResponse.getProcessInstanceKey()))
.isCompleted();
Inspection utilities
ZPT provides the InspectionUtility
to locate process instances and pass them to assertions. Some assertions also include methods to extract related entities, such as extractingProcessInstance()
or extractingLatestIncident()
.
CPT offers a similar utility via the ProcessInstanceSelector, which can be used with CamundaAssert.assertThatProcessInstance()
. For other entities, you can use the Camunda client to search for the entity and implement a custom assertion.
// ZPT:
InspectedProcessInstance childProcessInstance = InspectionUtility.findProcessInstances()
.withBpmnProcessId("child-process")
.findFirstProcessInstance()
.get();
BpmnAssert.assertThat(childProcessInstance).isCompleted();
// CPT:
CamundaAssert.assertThatProcessInstance(byProcessId("child-process"))
.isCompleted();
ZeebeTestEngine utilities
ZPT provides the ZeebeTestEngine
utilities to interact with the runtime, for example, to advance time.
CPT offers a similar utility via the CamundaProcessTestContext, but the following utilities are not supported:
waitForIdleState(duration)
waitForBusyState(duration)
CPT does not require these utilities because it provides blocking assertions that wait until the expected condition is fulfilled.
// ZPT
engine.waitForIdleState(duration);
engine.increaseTime(Duration.ofDays(1));
// CPT:
assertThat(processInstance).hasActiveElements("timer_event");
processTestContext.increaseTime(Duration.ofDays(1));
Next steps
Congratulations! Your process tests should now be fully migrated to CPT and running successfully.
When you’re ready, take the next steps to continue your journey:
- Explore new assertions
- Simplify your tests with new utilities
- Generate process test coverage reports (coming soon)
Troubleshooting
If you encounter issues with the migration or notice missing features, please report them in the Camunda GitHub repository.