Skip to main content
Version: 8.8 (unreleased)

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.

note

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 or spring-boot-starter-camunda-test-testcontainer),
    replace it with CPT’s Spring integration module.

  • If you use ZPT without Spring
    (artifactId: zeebe-process-test-extension or zeebe-process-test-extension-testcontainer),
    replace it with CPT’s Java module.

In your Maven pom.xml, add the dependency:

<dependency>
<groupId>io.camunda</groupId>
<artifactId>camunda-process-test-spring</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:

  1. Install Camunda 8 Run
    Follow the installation guide on your machine.

  2. Enable the management clock endpoint
    See prerequisites:

    • Create an application.yaml file in the root /c8run directory.
    • Add:
      zeebe.clock.controlled: true
  3. Start Camunda 8 Run.

  4. Switch CPT’s runtime mode to remote in your project configuration.

In your application.yml (or application.properties):

camunda:
process-test:
runtime-mode: remote

Migrate your process tests

Now, it's time to migrate your process tests.

First, migrate the general test class structure:

  1. Replace annotations and types

    • Replace @ZeebeSpringTest with @CamundaSpringProcessTest
    • Replace the type ZeebeTestEngine with CamundaProcessTestContext
  2. 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();
}

}

This is the equivalent CPT test class:

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();
}

}

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.