Utilities
There are different utilities that can help you to write your process test.
Manipulate the clock
The Camunda runtime uses an internal clock to execute process instances and to calculate when a BPMN timer event is due. In a test, you can use CamundaProcessTestContext
to manipulate the clock.
When to use it:
- Trigger an active BPMN timer event
- Test scenarios that require a specific date or time, for example, a leap year
@Test
void shouldTriggerTimerEvent() {
// given: a process instance waiting at a BPMN timer event
// when
assertThat(processInstance).hasActiveElements("wait_2_days");
processTestContext.increaseTime(Duration.ofDays(2));
// then
assertThat(processInstance).hasCompletedElements("wait_2_days");
}
Mock job workers
You can mock a job worker to simulate its behavior without invoking the actual worker. The mock handles all jobs of the given job type.
When to use it:
- Test the process in isolation from the actual job workers
- Simulate different outcomes of a job worker (success, BPMN error)
- Mock disabled job workers or Connectors
Complete job
The mock completes jobs with/without variables.
@Test
void shouldCompleteJob() {
// given: mock job worker for the job type "send-email"
// 1) Complete jobs without variables
rocessTestContext.mockJobWorker("send-email").thenComplete();
// 2) Complete jobs with variables
final Map<String, Object> variables = Map.of(
"emailSent", true,
"timestamp", "2024-01-01T10:00:00Z"
);
processTestContext.mockJobWorker("send-email").thenComplete(variables);
// when: create a process instance
// then: verify that the process instance completed all tasks
}
Throw BPMN error
The mock throws BPMN errors for jobs with the given error code and with/without variables.
@Test
void shouldThrowBpmnError() {
// given: mock job worker for the job type "validate-order"
// 1) Throw BPMN errors with error code "INVALID_ORDER"
processTestContext.mockJobWorker("validate-order").thenThrowBpmnError("INVALID_ORDER");
// 2) Throw BPMN errors with error code "INVALID_ORDER" and variables
final Map<String, Object> variables = Map.of(
"reason", "The order exceeds the item limit."
);
processTestContext
.mockJobWorker("validate-order")
.thenThrowBpmnError("INVALID_ORDER", variables);
// when: create a process instance
// then: verify that the process instance handled the BPMN error
}
Custom handler
You can implement a custom handler to mock more complex behaviors.
@Test
void shouldUseCustomHandler() {
// given: mock job worker for the job type "calculate-discount"
processTestContext
.mockJobWorker("calculate-discount")
.withHandler(
(jobClient, job) -> {
final Map<String, Object> variables = job.getVariablesAsMap();
final double orderAmount = (double) variables.get("orderAmount");
final double discount = orderAmount > 100 ? 0.1 : 0.0;
jobClient.newCompleteCommand(job).variable("discount", discount).send().join();
});
// when: create a process instance
// then: verify that the process instance has the expected variables
}
Mock child processes
You can mock a child process for a call activity to simulate its output without executing the actual child process. The mock deploys a dummy process with the given process ID that returns the given variables.
When to use it:
- Test the parent process in isolation from the actual child process
- Simulate different outcomes of a child process
- Mock a non-existing child process
@Test
void shouldMockChildProcess() {
// given: mock child process with the process ID "payment-process"
// 1) Complete the child process without variables
processTestContext.mockChildProcess("payment-process");
// 2) Complete the child process with variables
final Map<String, Object> variables = Map.of(
"paymentStatus", "completed",
"transactionId", "TXN-12345"
);
processTestContext.mockChildProcess("payment-process", variables);
// when: create a process instance
// then: verify that the process instance completed the call activity
}
Mock DMN decisions
You can mock a DMN decision for a business rule task to simulate its output without evaluating the actual DMN decision. The mock deploys a dummy DMN decision with the given decision ID that returns the given variables.
When to use it:
- Test the process with the business rule task in isolation from the actual DMN decision
- Simulate different outcomes of a DMN decision
- Mock a non-existing DMN decision
@Test
void shouldMockDmnDecision() {
// given: mock DMN decision with the decision ID "credit-check-decision"
final Map<String, Object> variables = Map.of(
"approved", true,
"riskLevel", "low",
"creditLimit", 5000
);
processTestContext.mockDmnDecision("credit-check-decision", variables);
// when: create a process instance
// then: verify that the process instance completed the business rule task
}