Skip to main content
Version: 8.9 (unreleased)

Configuration

By default, CPT uses a runtime based on Testcontainers. You can customize the runtime to your needs, or replace it with a Remote runtime, for example, if you can't install a Docker runtime.

Testcontainers runtime

The default runtime of CPT is based on Testcontainers. It uses the Camunda Docker image and includes the following components:

  • Camunda
  • Connectors
Why Testcontainers?

CPT follows a common practice by using Testcontainers to provide an isolated, reproducible, and easily configurable environment using Docker containers. This ensures consistent test results, simplifies setup across different platforms, and allows integration with Camunda and other components without manual installation or complex dependencies.

Shared runtime

If you use the same runtime configuration for all test classes, then you can use a shared runtime to speed up the test execution.

Prerequisites

  • A Docker-API compatible container runtime, such as Docker on Linux or Docker Desktop on Mac and Windows. If you're experiencing issues with your Docker runtime, have a look at the Testcontainers documentation.

Usage

By default, the runtime uses the same version of the Camunda Docker images as the Maven module. You can change the Docker images and other runtime properties in the following way.

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

camunda:
process-test:
# Change the version of the Camunda Docker image
camunda-docker-image-version: 8.8.0
# Change the Camunda Docker image
camunda-docker-image-name: camunda/camunda
# Set additional Camunda environment variables
camunda-env-vars:
env_1: value_1
# Expose additional Camunda ports
camunda-exposed-ports:
- 9000
# Change the Camunda logger name
camunda-logger-name: tc.camunda
# Enable Connectors
connectors-enabled: true
# Change the Connectors Docker image
connectors-docker-image-name: camunda/connectors
# Change version of the Connectors Docker image
connectors-docker-image-version: 8.8.0
# Set additional Connectors environment variables
connectors-env-vars:
env_1: value_1
# Set Connectors secrets
connectors-secrets:
secret_1: value_1
# Expose additional Connectors ports
connectors-exposed-ports:
- 9010
# Change the Connectors logger name
connectors-logger-name: tc.connectors

Shared runtime

By default, CPT creates a new runtime for each test class. You can change this behavior and use a shared Testcontainers runtime for all test classes to speed up the test execution. You can enable the shared runtime in the following way.

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

camunda:
process-test:
# Switch from a managed to a shared runtime
runtime-mode: shared

All test classes using the shared runtime will use the same runtime configuration. You can't change the runtime configuration for individual test classes, such as enabling connectors or setting connector secrets. However, you can switch to a managed runtime for individual test classes and override the runtime configuration.


@SpringBootTest(
properties = {
// Use a managed runtime for a different configuration
"camunda.process-test.runtime-mode=managed",
"camunda.process-test.connectors-enabled=true",
}
)
@CamundaSpringProcessTest
public class MyProcessTest {
//
}

Multi-tenancy

Multi-tenancy is disabled by default. You can enable multi-tenancy in the following way:

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

camunda:
process-test:
# Enable multi-tenancy
multi-tenancy-enabled: true

By enabling multi-tenancy, the runtime enables Basic Auth security and creates a default user with username/password demo with admin rights to interact with the runtime.

A process test using multi-tenancy could look like the following example:


@SpringBootTest
@CamundaSpringProcessTest
public class MyProcessTest {

private static final String DEFAULT_USERNAME = "demo";

private static final String TENANT_ID_1 = "tenant-1";
private static final String TENANT_ID_2 = "tenant-2";

@Autowired
private CamundaClient client;
@Autowired
private CamundaProcessTestContext processTestContext;

private CamundaClient clientForTenant1;

@BeforeEach
void setupTenants() {
// create tenants
client.newCreateTenantCommand().tenantId(TENANT_ID_1).name(TENANT_ID_1).send().join();
client.newCreateTenantCommand().tenantId(TENANT_ID_2).name(TENANT_ID_2).send().join();

// assign the default user to the tenants
client
.newAssignUserToTenantCommand()
.username(DEFAULT_USERNAME)
.tenantId(TENANT_ID_1)
.send()
.join();
client
.newAssignUserToTenantCommand()
.username(DEFAULT_USERNAME)
.tenantId(TENANT_ID_2)
.send()
.join();

// create a client for tenant 1
clientForTenant1 =
processTestContext.createClient(
clientBuilder -> clientBuilder.defaultTenantId(TENANT_ID_1));
}

@Test
void createProcessInstance() {
// given
clientForTenant1
.newDeployResourceCommand()
.addResourceFromClasspath("bpmn/order-process.bpmn")
.send()
.join();

// when
final var processInstance =
clientForTenant1
.newCreateInstanceCommand()
.bpmnProcessId("order-process")
.latestVersion()
.variable("order_id", "order-1")
.send()
.join();

// then
assertThatProcessInstance(processInstance).isCreated();

Assertions.assertThat(processInstance.getTenantId()).isEqualTo(TENANT_ID_1);
}
}
info

You should assign the default user (demo) to all tenants to ensure that the assertions can access all data.

Custom containers

You can add custom containers to the managed or shared Testcontainers runtime, for example, to add a database, an MCP server, or a mock service.

The CPT runtime manages the lifecycle of the custom containers and ensures that they are started before the tests and stopped after the tests. The custom containers are added to the same network as the Camunda and Connectors containers to allow communication between the containers.

You can add a custom container in the following way.

Implement a CamundaProcessTestContainerProvider bean that creates the custom container.

In this example, we create a WireMock container to mock external HTTP calls in the tests.

@Configuration
public class TestConfig {

@Bean
public CamundaProcessTestContainerProvider wireMockProvider() {
return containerContext -> new WireMockContainer();
}

// A WireMock container to mock external HTTP calls in the tests
private static final class WireMockContainer extends GenericContainer<WireMockContainer> {
public WireMockContainer() {
// Configure the Docker image
super("wiremock/wiremock:3.13.0");
// Configure the network alias for communication between the containers
withNetworkAliases("wiremock");
// Configure the ports to expose
withExposedPorts(8080);
// Configure the logger
withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("tc.wiremock"), true));
// Configure the wait strategy to ensure that the container is ready before running the tests
waitingFor(
Wait.forHttp("/__admin/mappings").forPort(8080).withMethod("GET").forStatusCode(200));
// Custom container-specific configuration
withCopyFileToContainer(
// Copy the WireMock mapping file for the HTTP stubs to the container
MountableFile.forClasspathResource("/wiremock/mapping.json"),
"/home/wiremock/mappings/mapping.json");
}
}
}

In the application.yml configuration, we use a connector secret to bind the connector task to the WireMock container using its network alias wiremock and the exposed port 8080.

camunda:
process-test:
connectors-enabled: true
connectors-secrets:
BASE_URL: http://wiremock:8080

Remote runtime

Instead of using the managed Testcontainers runtime, you can configure CPT to connect to a remote runtime, for example, to a local Camunda 8 Run running on your machine.

When to use it:

  • You can't install a Docker-API compatible container runtime
  • Debugging of test case on your local machine
info

You are responsible for configuring and managing the remote runtime. Ensure the runtime is running before executing tests. Keep in mind that CPT automatically deletes all data between test runs to maintain a clean state.

Prerequisites

  • Install a Camunda 8 runtime, for example, Camunda 8 Run
  • Expose the management API port (9600) to delete the data between test runs (by default for a local Camunda 8 Run)
  • Enable the management clock endpoint to allow clock manipulations

You can configure Camunda 8 Run by defining a application.yaml file with:

zeebe.clock.controlled: true

By default, Camunda 8 Run loads the application.yaml from the distribution's root directory. If you use a different path, then you need to set the path when starting the application with the command line argument --config=application.yaml:

./start.sh --config=application.yaml

Usage

You need to set the following property to switch to a remote runtime.

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

camunda:
process-test:
# Switch from a managed to a remote runtime
runtime-mode: remote

Change the connection

By default, CPT connects to a remote Camunda 8 Run running on your local machine. CPT checks if the remote runtime is available and ready, before running the tests. It waits up to 1 minute for the remote runtime to become ready.

You can change the connection to the remote runtime and the connection time in the following way.

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

camunda:
process-test:
runtime-mode: remote
# Change the connection (default: Camunda 8 Run)
remote:
camunda-monitoring-api-address: http://0.0.0.0:9600
connectors-rest-api-address: http://0.0.0.0:8085
# The connection timeout in ISO-8601 duration format (default: PT1M)
runtime-connection-timeout: PT1M
client:
rest-address: http://0.0.0.0:8080
grpc-address: http://0.0.0.0:26500

Debugging of test cases

You can use a remote runtime to debug your test cases on your local machine. Set breakpoints in your test case and run the test in debug mode from your IDE.

When the test execution stops at a breakpoint, you can inspect the process instance state using Operate and the user task state using Tasklist. You can also use the Camunda client to interact with the runtime from the debugger console.

Process Test Coverage

CPT generates an HTML and JSON coverage report of your BPMN processes. You can configure the report generation in the following way.

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

camunda:
process-test:
coverage:
# Change the directory where the report is generated
reportDirectory: target/coverage-report
# Exclude processes from the report
excludedProcesses:
- process_1
- process_2

Logging

The test runtime uses SLF4J as the logging framework. If needed, you can enable the logging for the following packages:

  • io.camunda.process.test - The test runtime (recommended level info)
  • tc.camunda - The Camunda Docker container (recommended level error)
  • tc.connectors - The connectors Docker container (recommended level error)
  • org.testcontainers - The Testcontainers framework (recommended level warn)