4

I am able to run a Spring Boot application with Camunda for workflow management. My pom.xml with Camunda related dependencies are shown below.

<dependencyManagement>
        ...
        <dependency>
            <groupId>org.camunda.bpm</groupId>
            <artifactId>camunda-bom</artifactId>
            <version>7.15.0</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>

    <dependency>
        <groupId>org.camunda.bpm.springboot</groupId>
        <artifactId>camunda-bpm-spring-boot-starter</artifactId>
        <version>7.15.0</version>
    </dependency>

    <!-- REST API -->
    <dependency>
        <groupId>org.camunda.bpm.springboot</groupId>
        <artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
        <version>7.15.0</version>
    </dependency>

    <!-- dashboard -->
    <dependency>
        <groupId>org.camunda.bpm.springboot</groupId>
        <artifactId>camunda-bpm-spring-boot-starter-webapp</artifactId>
        <version>7.15.0</version>
    </dependency>

    <dependency>
        <groupId>org.camunda.bpm</groupId>
        <artifactId>camunda-engine-plugin-spin</artifactId>
    </dependency>

    <dependency>
        <groupId>org.camunda.spin</groupId>
        <artifactId>camunda-spin-dataformat-all</artifactId>
    </dependency>

I have just one .BPMN file. My application.yml file looks like this:

spring.main.banner-mode: console
server.port: 9090

springdoc:
  model-and-view-allowed: true
  swagger-ui:
    operationsSorter: alpha

spring.jpa:
  hibernate:
    ddl-auto: none
  show-sql: true
  properties:
    hibernate:
      format_sql: true
spring.datasource:
  initialization-mode: always
  platform: postgres
  url: jdbc:postgresql://xxxx
  username: xxxx
  password: xxxx

spring.flyway.enabled: false

camunda.bpm:
  admin-user:
    id: demo
    password: demo
  generic-properties:
    properties:
      generalResourceWhitelistPattern: "[a-zA-Z0-9,'_\\$\\-\\.\\+\\!\\*\\(\\)]+|camunda-admin"

In the codes, all I have to do are just to declare the Camunda objects and I can used them without further setups:

@AutoWired
protected final RuntimeService runtimeService;

@AutoWired
protected final TaskService taskService;

@AutoWired
protected final IdentityService identityService;

Now I am trying to write unit tests. It seems that there are more than one way to set up Camunda for unit testing, but I am not able to get any of the examples I found working. By some trial and error, I managed to get the following codes to set up Camunda for unit test.

@ActiveProfiles("test")
public class EntitlementServiceTest {

    private RuntimeService runtimeService;
    private TaskService taskService;
    private IdentityService identityService;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        ProcessEngine processEngine = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration()
            .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE)
            .setJdbcUrl("jdbc:h2:mem:database_user;DB_CLOSE_ON_EXIT=FALSE")
            .setJobExecutorActivate(true)
            .buildProcessEngine();
        runtimeService = processEngine.getRuntimeService();
        taskService = processEngine.getTaskService();
        identityService = processEngine.getIdentityService();
    }

    ...
}

But I am not sure if this is the correct way to do so, so it would be better if someone points this out. The codes don't seem to have loaded anything from the application file for unit testing, application-test.yml. Replacing the hardcoded JDBC URL with ${spring.datasource.url} does not work at all. And even though I have set the camunda.bpm.generic-properties.properties.generalResourceWhitelistPattern, application-test.yml, it is obvious that it is not being read.

user3573403
  • 1,780
  • 5
  • 38
  • 64

1 Answers1

4

You have basically two ways to test a camunda spring boot application:

1st: run a camunda engine in memory, without spring. This can be very useful to test process flows, delegate behavior and so on. In that case, you will use the "ProcessEngineRule" from the core (junit4 style) or the junit5 extension (camunda-bpm-junit5). You will probably mock a lot of services and repos because you focus on the camunda flow. You do not need to annotate with "ActiveProfiles", as you are not running a spring context.

2nd: Run your tests using the SpringRunner or the SprinExtension and let spring handle the engine setup. This is just a plain spring boot test which will run everything you specify via yml and profiles and you will be able to inject all the camunda services.

Neither of these approaches is "better", they focus on different things. According to the testing pyramid, you would have many "real" unit tests, that do not even run camunda in memory just to verify your code works, some rule-based flow tests and a few integration tests using spring boot tests.

The camunda best practices guide will help configuring the scenarios: https://camunda.com/best-practices/testing-process-definitions/

Sidenote: When you mix plain-unit and spring integration tests, you should switch to constructor based injection to make it easier to manually create instances of your services without using reflection.

Jan Galinski
  • 11,768
  • 8
  • 54
  • 77
  • 1
    I managed to set up the unit test with the first approach (without spring boot). I had to put in a camunda.cfg.xml file in test/resources just for the test. For the BPMN file, it seems to be able to pick up from main/resources even though I specified @Deployment(resources = "process.bpmn") – user3573403 Sep 29 '21 at 09:09
  • 1
    As for the second approach with Spring Boot, I can't seem to find any workable codes. I am aware of the link that you provided but that seems to be for the first approach. – user3573403 Sep 29 '21 at 09:10
  • Well, there is nothing really special to the spring itest ... you just run a spring boot test using your application as configuration ... so you got everything up and running and can autowire whatever you like ... – Jan Galinski Sep 29 '21 at 13:17