Integration Tests with Springboot + Jooq

Hello everyone,

I am absolutely new with Camunda and I hope you can help me.

Currently, I’m trying to realize a new project via Camunda.

In short, the scenario: When a customer orders a pizza, the order ID is written from the order system into a Message Queue. The new Springboot application listens to the queue via JMS listener and starts -if necessary- a new Camunda process with the order id as BusinessKey (so I don’t start the Camunda process via REST API). During the Camunda process, various information is gathered in the “Service Tasks” (implemented using JavaDelegate) from the back end (via Jooq accesses) or written back to the database.

Now that everything has been implemented, I would like to write an integration test that maps a complete process flow in Camunda. I would like to start by giving Camunda an Order ID and then assisting Service Task by Service Task with the process steps.
For example: If the correct data was read from the tables during the “Read Information” task and the correct data was written back to the database during the “Update Data” task and so on…

So can I start Camunda in a test case and go to the first task, work through it and assert the process context before I go to the second task? Is it still possible to tell Camunda to go to the second task and then stop at the end of the second task so that I can assert the tables in the database?

My IT-Class looks like:

   @TestPropertySource("classpath:test.properties")
   @SpringBootTest(classes = PizzaDataUpdateProcess.class,
       properties = {
           "camunda.bpm.generate-unique-process-engine-name=true",
           "camunda.bpm.generate-unique-process-application-name=true",
           "spring.datasource.generate-unique-name=true",
       })
   @RunWith(SpringRunner.class)
   @Deployment(resources = {"bpmn/Pizza_Update_Process.bpmn"})
   @Transactional
   public class CamundaProzessIT {

     private static final Logger LOG = LoggerFactory.getLogger(CamundaProzessIT.class);

     @Autowired
     RuntimeService runtimeService;

     @Autowired
     private JooqTestCopyUtil copyUtil;

     @Test
     public void camundaTest_IT() throws Exception {

       LOG.info("camundaTest_IT:");

       final Integer copyID = copyUtil.getKatalogEintragCopy("PIZZA_UPDATE_PROCESS_IT_01");   
       final ProcessInstance instance = runtimeService
           .startProcessInstanceByKey(PIZZA_UPDATE_PROCESS_KEY, copyID);
   		
   	// Now the Magic
   	
   	//Go To Task 1 and assertThat()....
   	
   	//Now go to Task 2 and Select Record --> assert Record ....
   		
   	}		

   }

If I add

@Rule
 public ProcessEngineRule processEngineRule = new ProcessEngineRule();

I get the following Problem:

org.camunda.bpm.engine.ProcessEngineException: ENGINE-03018 Could not check if tables are already present using metadata.

	at org.camunda.bpm.engine.impl.db.EnginePersistenceLogger.checkDatabaseTableException(EnginePersistenceLogger.java:241)
	at org.camunda.bpm.engine.impl.db.sql.DbSqlSession.isTablePresent(DbSqlSession.java:523)
	at org.camunda.bpm.engine.impl.db.sql.DbSqlSession.isEngineTablePresent(DbSqlSession.java:463)
	at org.camunda.bpm.engine.impl.db.AbstractPersistenceSession.dbSchemaUpdate(AbstractPersistenceSession.java:218)
	at org.camunda.bpm.engine.impl.SchemaOperationsProcessEngineBuild.execute(SchemaOperationsProcessEngineBuild.java:56)
	at org.camunda.bpm.engine.impl.SchemaOperationsProcessEngineBuild.execute(SchemaOperationsProcessEngineBuild.java:34)
	at org.camunda.bpm.engine.impl.interceptor.CommandExecutorImpl.execute(CommandExecutorImpl.java:28)
	at org.camunda.bpm.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:110)
	at org.camunda.bpm.engine.impl.interceptor.ProcessApplicationContextInterceptor.execute(ProcessApplicationContextInterceptor.java:70)
	at org.camunda.bpm.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:33)
	at org.camunda.bpm.engine.impl.ProcessEngineImpl.executeSchemaOperations(ProcessEngineImpl.java:120)
	at org.camunda.bpm.engine.impl.ProcessEngineImpl.<init>(ProcessEngineImpl.java:93)
	at org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl.buildProcessEngine(ProcessEngineConfigurationImpl.java:815)
	at org.camunda.bpm.engine.impl.test.TestHelper.getProcessEngine(TestHelper.java:476)
	at org.camunda.bpm.engine.test.ProcessEngineRule.initializeProcessEngine(ProcessEngineRule.java:179)
	at org.camunda.bpm.engine.test.ProcessEngineRule.apply(ProcessEngineRule.java:159)
	at org.junit.rules.RunRules.applyAll(RunRules.java:26)
	at org.junit.rules.RunRules.<init>(RunRules.java:15)
	at org.junit.runners.BlockJUnit4ClassRunner.withTestRules(BlockJUnit4ClassRunner.java:400)
	at org.junit.runners.BlockJUnit4ClassRunner.withRules(BlockJUnit4ClassRunner.java:356)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.withRulesReflectively(SpringJUnit4ClassRunner.java:313)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:303)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.apache.ibatis.exceptions.PersistenceException: 
### Error getting a new connection.  Cause: java.sql.SQLException: Error setting driver on UnpooledDataSource. Cause: java.lang.ClassNotFoundException: org.h2.Driver
### Cause: java.sql.SQLException: Error setting driver on UnpooledDataSource. Cause: java.lang.ClassNotFoundException: org.h2.Driver
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.getConnection(DefaultSqlSession.java:300)
	at org.camunda.bpm.engine.impl.db.sql.DbSqlSession.isTablePresent(DbSqlSession.java:498)
	... 41 more
Caused by: java.sql.SQLException: Error setting driver on UnpooledDataSource. Cause: java.lang.ClassNotFoundException: org.h2.Driver
	at org.apache.ibatis.datasource.unpooled.UnpooledDataSource.initializeDriver(UnpooledDataSource.java:221)
	at org.apache.ibatis.datasource.unpooled.UnpooledDataSource.doGetConnection(UnpooledDataSource.java:200)
	at org.apache.ibatis.datasource.unpooled.UnpooledDataSource.doGetConnection(UnpooledDataSource.java:196)
	at org.apache.ibatis.datasource.unpooled.UnpooledDataSource.getConnection(UnpooledDataSource.java:93)
	at org.apache.ibatis.datasource.pooled.PooledDataSource.popConnection(PooledDataSource.java:385)
	at org.apache.ibatis.datasource.pooled.PooledDataSource.getConnection(PooledDataSource.java:89)
	at org.apache.ibatis.transaction.jdbc.JdbcTransaction.openConnection(JdbcTransaction.java:138)
	at org.apache.ibatis.transaction.jdbc.JdbcTransaction.getConnection(JdbcTransaction.java:60)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.getConnection(DefaultSqlSession.java:298)
	... 42 more

My cfg.xml-File in the resources-Folder is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.springframework.org/schema/beans"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean class="org.camunda.bpm.engine.impl.cfg.StandaloneProcessEngineConfiguration" id="processEngineConfiguration">

    <property name="jdbcUrl" value="jdbc:h2:mem:camunda;DB_CLOSE_DELAY=1000"/>
    <property name="jdbcDriver" value="org.h2.Driver"/>
    <property name="jdbcUsername" value="sa"/>
    <property name="jdbcPassword" value=""/>

    <property name="databaseSchemaUpdate" value="true"/>

    <property name="jobExecutorActivate" value="false"/>

  </bean>

</beans>

Hope you can help me. Thanks in advance.

Is this kind of testing even possible ?

Hi @ckcyber,

yes they are possible. You can autowire the process engine in the test and register this engine with the camunda-bpm-assert library. They you can use assertions in your test.

Here is an example:

package com.camunda.consulting.integration;

import static org.assertj.core.api.Assertions.*;
import static org.camunda.bpm.engine.test.assertions.ProcessEngineTests.*;

import org.camunda.bpm.client.ExternalTaskClient;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;

import com.camunda.consulting.NotificationWorker;
import com.camunda.consulting.testEngine.CamundaTestApplication;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = CamundaTestApplication.class, webEnvironment = WebEnvironment.DEFINED_PORT)
public class NotificationWorkerIntegrationTest {
  
  @Autowired
  ProcessEngine engine;
  
  @Before
  public void setup() {
    init(engine);
  }
  
  public static final String TOPIC_TO_TEST = "notification";
  
  @Test
  public void testNotificationWorker() throws InterruptedException {
    // start a process instance
    ProcessInstance processInstance = engine.getRuntimeService().startProcessInstanceByKey("ExternalWorkerTestProcess", 
        withVariables(
            "topic", TOPIC_TO_TEST, 
            "content", "myTestContent"));
    
    // run through the process
    // ...
    
    // assert on the results
    assertThat(processInstance).isEnded().variables().contains(entry("message", "Sorry, your tweet has been rejected: myTestContent"));
  }
  
}

Hope this helps, Ingo

2 Likes

Hello @Ingo_Richtsmeier

Yes that helped. Thank you very much for your help.

Best regards

Hi, @Ingo_Richtsmeier
Can you say name of dependency com.camunda.consulting.testEngine.CamundaTestApplication?