Continue unit test from call-activity

Hi there, I have a model where a call-activity is invoked at a certain place, and I want to implement a unit test for it. Both the main and the sub process are deployed with the @Deployment annotation.

When the test is performing, it gets stuck at the call activity - I could prove because isWaitingAt(“subProcess”) returned true. So, I wanted to go on from there, and implemented execute(job()). This failed with a NullPointerException because job() returned null. What did I miss?

Many thanks in advance,
Christian

After some playing around, I found a solution: instead of using

execute(job())

I implemented my own query for the job that can be identified by the process definition key of the sub process:

	private Job queryJob(String processDefinitionKey)
	{
		Job result = processEngine
			.getManagementService()
			.createJobQuery()
			.active()
			.processDefinitionKey(processDefinitionKey)
			.singleResult();
		return result;
	}

	private ProcessInstance queryProcessInstance(String processDefinitionKey)
	{
		ProcessInstance result = processEngine
			.getRuntimeService()
			.createProcessInstanceQuery()
			.active()
			.processDefinitionKey(processDefinitionKey)
			.singleResult();
		return result;
	}

With these, I could control the progress in the sub process and query the sub processes instance

Hi @cjacob,

the job() method looks for the one job in the master process instance.
Please have a look at the other job(...) methods that BPM Assert provides. You can also pass on a processInstance for example or your own jobQuery.

That should help, I hope.

Best,
Tobias

I followed Fabio’s recommendation from this thread and refactored my test to use https://github.com/camunda-community-hub/camunda-platform-scenario and I was able to test my main process with the sub-process mocked:

import org.camunda.bpm.engine.delegate.BpmnError;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.test.mock.Mocks;
import org.camunda.bpm.engine.variable.VariableMap;
import org.camunda.bpm.engine.variable.Variables;
import org.camunda.bpm.scenario.ProcessScenario;
import org.camunda.bpm.scenario.Scenario;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestCamundaConfiguration.class})
public class MyTest {

private ProcessScenario processScenario = mock(ProcessScenario.class);

@Before
public void setup() {
    when(processScenario.waitsAtMockedCallActivity("MyCallActivityIdTheOneWillCallASubProcess"))
            .thenReturn(callActivity -> callActivity.complete(Collections.singletonMap(
                    "status", "1"))); // "status" is a sub-process-outgoing parameter required for the main process
}

@After
public void resetMocks() {
    Mocks.reset();
}

private ProcessInstance startProcess() {

    final VariableMap variables = Variables.createVariables()
            .putValue("request_id", "1")
            .putValue("request_colour", "blue");

    final Scenario scenario = Scenario.run(this.processScenario)
      .withMockedProcess("SubProcessNameId") // mocking sub process
      .startByKey("MainProcessNameId", variables)
      .execute();

    return scenario.instance(this.processScenario);
}

@Test
public void happyFlow() {

    final ProcessInstance processInstance = startProcess();

    // task2 is part of the sub process that was mocked
    assertThat(processInstance).hasPassedInOrder("start_event", "task1", "call_sub_process","task3");
}

}

In my case the process has multiple call activities. I mocked the first one by using @abelaneiros code and wanted to check, if the process waits at the second call activity afterwards (after passing some other user tasks in between).

However, I encountered the following exception:

java.lang.AssertionError: Process Instance {my-main-process:1:3, 11} waits at an unexpected CallActivity ‘my-second-call-activity’.

What’s even more confusing to me, is, that this activity is exactly where I expect the process to be:

assertThat(processInstance).isWaitingAt("my-second-call-activity");

Has someone encountered similar issues while testing?

Could you share your code? I need more context to understand

Hi @abelaneiros , I updated my description to provide more details. This is the code so far:

@RunWith(SpringJUnit4ClassRunner.class)
@Deployment(resources = {
    "processes/my-main-process.bpmn",
}
public class MyTest {

  @Test
  public void processShouldWaitAtSecondSubProcessCallActivity() {
    parameters.put("param1", true);

    when(processScenario.waitsAtMockedCallActivity("my-first-call-activity"))
        .thenReturn(callActivity -> callActivity.complete(null));

    final ProcessInstance processInstance = startProcess();

    assertThat(processInstance).hasPassed("some-user-task");
    assertThat(processInstance).hasPassed("some-gateway");
    assertThat(processInstance).hasPassed("some-service-task");
    assertThat(processInstance).isWaitingAt("my-second-call-activity");
  }

  private ProcessInstance startProcess() {
    Scenario scenario = Scenario.run(this.processScenario)
        .withMockedProcess("my-first-subprocess")
        .withMockedProcess("my-second-subprocess")
        .startByKey("my-main-process", parameters)
        .execute();

    return scenario.instance(this.processScenario);
  }
}

I would say you are getting Process Instance {my-main-process:1:3, 11} waits at an unexpected CallActivity ‘my-second-call-activity’ error because “my-second-call-activity” is not defined (or deployed) in your test context. Could you check that?

Could you share the definition of my-second-call-activity? Could you check that the “Called element” has
my-second-subprocess?

In which line do you get the exception?

Thanks for the input. I already tried to deploy it, with the following outcome, so I removed it again:

java.lang.AssertionError: Process ‘my-second-subprocess’ declared to be mocked, but it is already deployed. Please remove from your list of explicit deployments.

Definition of my-second-call-activity:

<callActivity id="my-second-call-activity" name="My second call activity" calledElement="my-second-subprocess">
    <extensionElements>
        <camunda:in businessKey="#{execution.processBusinessKey}" />
        <camunda:in variables="all" />
        <camunda:out variables="all" />
        <camunda:executionListener expression="#{someService.someMethod1()}" event="start" />
        <camunda:executionListener expression="#{someService.someMethod2(execution)}" event="end" />
    </extensionElements>
    ...
</callActivity>

I get the exception in the execute() line.

Did you try deploying it and removing the mocking part? I think this is the fix. I mocked my process because I did want to skip it, like your first sub-process, but if what you need if to check your current process is waiting for the second one execution, I wouldn’t mock it.

Try removing this line and deploying your sub-process:

.withMockedProcess("my-second-subprocess")

Yes, I tried that too, but I got the same error message, stating that the process is waiting at an unexpected call activity.

I have created and pushed an small example in github.
This is the url: GitHub - abelaneiros/camunda-testing-example

Don’t know why but the @Deployment annotation didn’t work for me. I deployed both process manually.

Maybe because the libraries and using are a bit old. I just copied and pasted from an old example that was working to save time.

Check the code and let me know if this help you! It is not exactly what you need because the second process is executed too.

1 Like

Hi @abelaneiros,

in your setup you have to configure the process engine for autodeployment of process models.

The @Deployment annotations requires a process engine managed by the JUnit test, as it is described for different JUnit versions here: Testing | docs.camunda.org

Hope this helps, Ingo

I was unable to do that with the current SpringFramework version I have in this example. Could you try in a different branch? I would love to see that

Hi @abelaneiros
thank you very much for your effort! I wasn’t able to solve the problem in my current environment (yet), however, I’m going to set up a new (smaller) test project based on your code to hopefully get this to work :slight_smile: