Unable to mock task Mocks.register(...)

Hi, I spent 2 days investigating comunda docs and videos from official channel and really got stuck.
I am trying to write simple integration test. Process is starting but mock registration is not working.
So i expect that my mocked task will be run when process is started but instead of it not mocked task is run.

I checked dependencies version compatibility and it’s ok. I am using jdk 17. It is sprinboot app running with jdk 11, but I’m trying to avoid springboottest annotation and unneccessary complexity.
Please share some knowledge on this problem.

pom dependencies:

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<camunda.spring-boot.version>7.17.0</camunda.spring-boot.version>
		<java.version>11</java.version>
<!--		<skipTests>true</skipTests>-->
<!--		<excludeTests>**/*IntegrationTest</excludeTests>-->
	</properties>
		<dependency>
			<groupId>org.camunda.bpm.springboot</groupId>
			<artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
			<version>${camunda.spring-boot.version}</version>
		</dependency>
<dependency>
			<groupId>org.junit.vintage</groupId>
			<artifactId>junit-vintage-engine</artifactId>
			<version>5.8.2</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-api</artifactId>
			<version>5.8.2</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.camunda.bpm</groupId>
			<artifactId>camunda-bpm-junit5</artifactId>
			<version>7.17.0</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.camunda.bpm</groupId>
			<artifactId>camunda-bpm-assert</artifactId>
			<version>7.17.0</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.assertj</groupId>
			<artifactId>assertj-core</artifactId>
			<version>3.21.0</version>
			<scope>test</scope>
		</dependency>
import com.si.app.process.service.ProcessRepositoryService;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.test.Deployment;
import org.camunda.bpm.engine.test.junit5.ProcessEngineExtension;
import org.camunda.bpm.engine.test.mock.Mocks;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.Mockito;
import org.springframework.test.util.ReflectionTestUtils;

import static org.assertj.core.api.Assertions.assertThat;
import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.*;

@ExtendWith(ProcessEngineExtension.class)
public class PreLaunchCheckTaskTest {
    
    @RegisterExtension
    ProcessEngineExtension extension = ProcessEngineExtension.builder()
            .configurationResource("camunda.cfg.xml")
            .build();

    @Test
    @Deployment(resources = "rv-reverify-contact_ver_4.bpmn")
    public void execute() {
        PreLaunchCheckTask preLaunchCheckTask = new PreLaunchCheckTask();
        Mocks.register("preLaunchCheckTask", preLaunchCheckTask);
        
        ProcessRepositoryService processRepositoryService = 
        Mockito.mock(ProcessRepositoryService.class);
        ReflectionTestUtils.setField(preLaunchCheckTask, "processRepositoryService", processRepositoryService);
        
        // Given we create a new process instance
        ProcessInstance processInstance = runtimeService().startProcessInstanceByKey("ReverifyContact");
// etc
}

Code to be tested

@Component
public class PreLaunchCheckTask extends ReverifyBaseTask {
  @Override
    public void execute(DelegateExecution execution) throws Exception {
               String mainProcessUUID = execution.getProcessBusinessKey();
        String subProcessUUID = (String) execution.getVariable(BPMProcessConfigNames.assigneeSubJobUUID.configName());
  
        String mainProcessInstanceID = execution.getProcessInstanceId();
        String subProcessInstanceID = execution.getActivityInstanceId();

        processRepositoryService.updateBpmSubProcessExecution(mainProcessUUID, mainProcessInstanceID,
                subProcessUUID, subProcessInstanceID);
}
}

public abstract class ReverifyBaseTask extends CommonBPM implements JavaDelegate {
//bussiness logic
}

@Component
public class CommonBPM {

    @Autowired
    protected ProcessRepositoryService processRepositoryService;
//bussiness logic
}

I got NPE on updateBpmSubProcessExecution cause processRepositoryService is null. So my preLaunchTask is not registered in testing process (I see in debug that running task and mocked one are different objects and that’s why I inject via reflection in not used in test mocked object)

I hope, code is crystal clear, I ommited excessive details

java.lang.NullPointerException: Cannot invoke “com.si.app.process.service.ProcessRepositoryService.updateBpmSubProcessExecution(String, String, String, String)” because “this.processRepositoryService” is null

Hi Ianis.

Can you by chance share your project on Github or the like? It would be the easiest to reproduce your problem to diagnose further.

And I wonder why you are not using the common Spring Boot Test setup - as this is proven to work (like for example in camunda-demo-starter/ProcessTest.java at main · camunda-consulting/camunda-demo-starter · GitHub)?

Best
Bernd

Hi, Bernd. Thanks for reply. Happy to see that my question doesn’t remain unanswered.
It took me a lot of effort to resolve this problem. I think I learnt your video about testing by heart:))
For now I only one person who starts develop integration test for startup code, that has almost zero unit/integration tests for several microservices, Yes, it happens. I am trying to start from something simple without springBootTest and I saw you advise the way in your video how to manage things without it.
I am rookie at camunda, and here is what I found out.

Problem with registering mock was due to 2 properties don’t work together:
camunda:delegateExpression and camunda:class. It is for sure breaking registration. So your task simply is not mocking. (for camunda platform 7.17)
Example(not working):
<bpmn:serviceTask id=“PROCESS_INITIATED” name=“PROCESS_INITIATED: Pre Launch Check” camunda:class=“com.si.app.workflow.adapter.rv.PreLaunchCheckTask” camunda:delegateExpression="${preLaunchCheckTask}">

So I fixed it by removing camunda:class property. Registering also doesn’t work without camunda:delegateExpression.
There is nothing in camunda docs about this fact(conflict of two properties) and I found it just via multiple tries. I think there should be added additional info about it.

Hi @Ianis,

Usually the camunda modeler switches the extension if you switch the implementation in the property panel:
grafik

With tool did you use to edit your process models?

Hope this helps, Ingo

Hi @Ingo_Richtsmeier No, I did it manually but I still think this should be mentioned in docs.
I was good example of developer which just trying to get familiar with product and got stuck right at the beginning. It is minimal that I can kindly ask from team. Maximum it will be good end-to-end examples in github and links in camunda docs.
I really don’t know where should I searching the reference to https://github.com/circleback/orchestration-api/pull/698 for example (may be I am naive and missed the reference?)
Please make our life easier, guys. Thank you for your high-quality product, I do like the api and additional test features, everything awesome, but docs, docs, docs

Hi @Ianis,

I’ve created a pull request to the docs with your suggestion: Suggestion from the Forum by ingorichtsmeier · Pull Request #1235 · camunda/camunda-docs-manual · GitHub

You can add your findings in more details to other parts of the docs as well (with more pull requests). Each page contains a link to the github source on the top:

Hope this helps, Ingo

1 Like

Hi, @Ingo_Richtsmeier I decided to not create new topic and ask here.
By the way is there any solution to use camunda:class property to register mock task?
As I see registration works only via camunda:delegation.

Hi @Ianis,

no, the engine uses reflection to call the execute() method. There is no framework to hook into Java reflection.

Hope this helps, Ingo

@Ingo_Richtsmeier Thanks a lot for clarification