Welcome to the next post in our blog series: “Treat your processes like code – test them!”

You can find the last post: “Testing entire process paths” here.

Today’s topic is “Testing process dependencies”. For the execution of a model, there are often additional resources required. This might be source code or the dependency on other models. But how can we deal with this when testing our models? In this post we will take a closer look at the following dependencies:

  • Models: Dependencies to BPMN diagrams referenced by the executed model
  • Code: Dependencies on source code referenced in the BPMN.

We will get to know another library that will help us with testing: camunda-bpm-mockito. The examples for this blog post can be found in this GitHub repository.

In the last post, we took a closer look at a small ordering process and tested it. Now we want to extend it and include additional features that we have to account for in our tests:

  • Another process that is referenced by a Call Activity
  • A Java Delegate that has additional dependencies to a service

Dependencies on other BPMN models

There are several reasons to include BPMN diagrams as Call Activities or to start them from within the code:

  • Reducing complexity: Extensive BPMN models can have a negative impact on the understanding of the actual process flow. Therefore, it is sometimes useful to outsource technical details and particularities to a separate diagram.
  • Reusability of components: As the number of automated processes increases, so does the number of functions that can be used in different places. If these are not just simple service calls, it can make sense to outsource these functions into separate processes.
  • Starting processes: Sometimes it is necessary to start processes asynchronously. This can be the case if further processing steps are to be performed after an instance has ended, without the process having to wait for their completion.

All three cases lead to a dependency on another process model during testing. But how should we deal with this?

Using the referenced model

We could use and test the referenced model in a unit test. However, this is not recommended for the following reasons:

  • The BPMN model must be tested and the test case will become more extensive
  • Reusable components are unnecessarily tested multiple times
  • If there are different return values or errors in the referenced model, to which the process must respond, this leads to an enormous additional effort in the test case
  • The dependencies of the referenced model in the test case must be accounted for
  • Modifications in the referenced model affect the test case of the process

Using another model with the same key

Instead of using the referenced diagram, a custom model with the same key can be deployed, the result of which can be parameterized. This is done with a few lines of code:

BpmnModelInstance modelInstance = Bpmn.createExecutableProcess()

  Deployment deployment = rule.getProcessEngine()
          .addModelInstance("callActivity" + ".bpmn", modelInstance)

For simple models, this is certainly a viable option. There are, however, cases that lead to additional effort – for example, if there are different return values or errors in the referenced model to which the process has to respond.

Mocking the model using camunda-bpm-mockito

Instead of building our own mock of the model, we can use the camunda-bpm-mockito library. This offers the following advantages:

  • Clear tests that focus on the actual process
  • Errors in a used model do not affect the test of the parent process
  • Differences in the behavior of the referenced model can be simulated more easily
  • Shorter execution times for tests

Now let’s take a look at our order process. The delivery is to be outsourced as an independent, reusable process that is referenced as a Call Activity.

We will now reference this delivery process as a Call Activity in the order process. But how do we handle this in our test? There are two tasks for us:

  • Mocking the delivery process in the test
  • Write a separate test for the delivery process

Mocking the delivery process in a test

For this purpose we add the following to the defaultScenario() method:



In shouldExecuteOrderCancelled we have to adjust the behavior of the Call Activity Mock to throw an error during execution:

                .onExecutionDo(execution -> {
                    throw new BpmnError("deliveryFailed");

We are already done with defining different variants for our called order process – quite simple! There is much more you can do with camunda-bpm-mockito, just give it a try.

Writing a separate test for the delivery process

Next, we create a separate test class for the delivery process and adopt the methods shouldExecuteOrderCancelled and shouldExecuteDeliverTwice.

@Deployment(resources = "deliver-process.bpmn")
public class DeliveryProcessTest {

    public static final String PROCESS_KEY = "deliveryprocess";
    public static final String TASK_DELIVER_ORDER = "Task_DeliverOrder";
    public static final String VAR_ORDER_DELIVERED = "orderDelivered";
    public static final String END_EVENT_DELIVERY_COMPLETED = "EndEvent_DeliveryCompleted";
    public static final String END_EVENT_DELIVERY_CANCELLED = "EndEvent_DeliveryCancelled";

    public ProcessEngineRule rule = new ProcessEngineRule();

    private ProcessScenario testDeliveryProcess;

    public void defaultScenario() {

                .thenReturn(task -> {
                    task.complete(withVariables(VAR_ORDER_DELIVERED, true));

    public void shouldExecuteHappyPath() {


    public void shouldExecuteOrderCancelled() {
        when(testDeliveryProcess.waitsAtUserTask(TASK_DELIVER_ORDER)).thenReturn(task -> {
            taskService().handleBpmnError(task.getId(), "DeliveryCancelled");



    public void shouldExecuteDeliverTwice() {
        when(testDeliveryProcess.waitsAtUserTask(TASK_DELIVER_ORDER)).thenReturn(task -> {
            task.complete(withVariables(VAR_ORDER_DELIVERED, false));
        }, task -> {
            task.complete(withVariables(VAR_ORDER_DELIVERED, true));


        verify(testDeliveryProcess, times(2))

Dependencies on source code

Now let’s take a look at how we can deal with code dependencies:

  • Replace all dependencies with mocks
  • Provide the entire context
  • Provide specific classes with dependencies

If all dependencies are replaced by mocks, the test loses its validity. Providing the whole context instead would in turn miss the goal of a unit test, would be very time-consuming for larger applications, and would lead to longer test run times. The solution, therefore, has to be the last point. But which classes should be provided and which should be replaced by mocks?

Let’s look at this example using the Java delegate used in the send cancellation task and add a mailing service:

public class SendCancellationDelegate implements JavaDelegate {

    private final MailingService mailingService;

    public SendCancellationDelegate(MailingService mailingService) {
        this.mailingService = mailingService;

    public void execute(DelegateExecution delegateExecution) throws Exception {
        final String customer = (String) delegateExecution.getVariable("customer");


        delegateExecution.setVariable("cancellationTimeStamp", Instant.now().getEpochSecond());

This delegate reads a process variable, uses the mailing service to send the cancellation, and writes the time of cancellation back into the process. It is definitely a good idea to execute this delegate during a test case because it increases the significance of the test. Sending the mail, however, is not useful.

In summary: Classes referenced from the diagram should be executed if possible. Their dependencies in turn should be mocked.

For this purpose, we extend the test as follows:

  1. Create a MailingService mock:
  private MailingService mailingService;

2. Pass the mock to the delegate:

Mocks.register("sendCancellationDelegate", new SendCancellationDelegate(mailingService));

3. Do nothing when sendMail() is executed:


4. Check if the mailing service is invoked:

  public void shouldExecuteCancellationSent() {
      when(testOrderProcess.waitsAtUserTask(TASK_CHECK_AVAILABILITY)).thenReturn(task -> {
          task.complete(withVariables(VAR_PRODUCTS_AVAILABLE, false));

              .startByKey(PROCESS_KEY, withVariables(VAR_CUSTOMER, "john"))


      //verfiy execution of mailingService
      verify(mailingService, (times(1))).sendMail(any());

In complex contexts it can be difficult to keep track of all the mocks used in a test case. Instead, it makes more sense to outsource them to Factory Classes in order to also consider the dependencies among each other.


With the camunda-bpm-mockito library much more is possible. For example, you can mock messages that are to be correlated or you can simulate the result of a Camunda query. All these functions make it easier to test more complex processes.

This blog post was a first step into the testing of process dependencies. Code and models are often closely linked together, which also affects the scope of our test cases. However, the examples and recommendations shown in this post can help to simplify your own tests and reduce the effort.

But how do we know if the tests we have written are sufficient and cover all necessary parts of the process? And how can we monitor this? We will deal with this topic in our next post.

If you’d like to dive deeper into testing topics, check out Testing Cheesecake – Integrate Your Test Reports Easily with FlowCov, presented at CamundaCon LIVE 2020.1 and available free on-demand.

Dominik Horn is Co-Founder of FlowSquad — specialists in process automation and individual software development. Stay in touch with Flowsquad on TwitterGitHub or email — info@flowsquad.io.

  • Introducing the Camunda Community Hub

    Here at Camunda, we are consistently in awe of our open source community and the amazing things you create using Camunda. During Hacktoberfest last year, we were blown away by the enthusiasm and expertise that the community brought to Camunda projects and community extensions. Based on that experience, to further strengthen and support our community, we’re launching the Camunda Community Hub, a platform for community extensions that we hope will both inspire our current open source community extension Maintainers and encourage new contributors to get started.  The Camunda Community Hub is a GitHub Organization that serves as a single place to find Camunda open source community-contributed extensions. For maintainers, it’s a community of maintainers and Camunda employees that provides peer...

    Read more
  • Send Slack Messages direct from Camunda Cloud

    This article is the fourth in a series exploring fun, straightforward ways you can control workflows using Camunda Cloud — have a read of the others for some background if you’d like to see Camunda Cloud in action with Restzeebe, without a line of code: Is there an alternative to Spaghetti? How can you Teach a Workflow to Execute a specific task? Automate manual tasks with Camunda and Trello Do you use Slack? How about adding a level of automation to this widely used collaboration tool, that is making email obsolete in many organizations? Let’s say you already widely use Slack in your company and want to receive an active notification when a new user has registered to your service? You can create...

    Read more
  • Process Automation Centers of Excellence: the secret...

    Have you successfully implemented Process Automation technology in areas of your organization, but find yourself struggling to drive further adoption? Are organizational silos, ease of knowledge sharing and resistance to change slowing things down? You aren’t alone. Moving from pilot and lighthouse projects to a full Process Automation program is a challenge. But, there’s a solution — establishing Process Automation Centers of Excellence (CoE) to share best practices and drive organization-wide digital transformation. “If you had one team working on the pilot, and probably also the lighthouse project, they will not only have become very familiar with the technology and architecture, but will have learned a couple of valuable lessons the hard way. These are incredibly valuable experiences and you...

    Read more