5

I try to run JUnit test for a Camunda Spring Boot application. I followed Testing:

JUnit 4

Using the JUnit 4 style of writing unit tests, the ProcessEngineRule must be used. Through this rule, the process engine and services are available through getters. As with the ProcessEngineTestCase (see above), including this rule will look for the default configuration file on the classpath. Process engines are statically cached over multiple unit tests when using the same configuration resource.

The following code snippet shows an example of using the JUnit 4 style of testing and the usage of the ProcessEngineRule.

public class MyBusinessProcessTest {

  @Rule
  public ProcessEngineRule processEngineRule = new ProcessEngineRule();

  @Test
  @Deployment
  public void ruleUsageExample() {
    RuntimeService runtimeService = processEngineRule.getRuntimeService();
    runtimeService.startProcessInstanceByKey("ruleUsage");

    TaskService taskService = processEngineRule.getTaskService();
    Task task = taskService.createTaskQuery().singleResult();
    assertEquals("My Task", task.getName());

    taskService.complete(task.getId());
    assertEquals(0, runtimeService.createProcessInstanceQuery().count());
  }
}

But I get an error:

org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [activiti.cfg.xml]; nested exception is java.io.FileNotFoundException: class path resource [activiti.cfg.xml] cannot be opened because it does not exist
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:344)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
    at org.camunda.bpm.engine.impl.cfg.BeansConfigurationHelper.parseProcessEngineConfiguration(BeansConfigurationHelper.java:35)
    at org.camunda.bpm.engine.impl.cfg.BeansConfigurationHelper.parseProcessEngineConfigurationFromResource(BeansConfigurationHelper.java:50)
    at org.camunda.bpm.engine.ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(ProcessEngineConfiguration.java:305)
    at org.camunda.bpm.engine.ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(ProcessEngineConfiguration.java:301)
    at org.camunda.bpm.engine.impl.test.TestHelper.getProcessEngine(TestHelper.java:428)
    at org.camunda.bpm.engine.test.ProcessEngineRule.initializeProcessEngine(ProcessEngineRule.java:175)
    at org.camunda.bpm.engine.test.ProcessEngineRule.apply(ProcessEngineRule.java:154)
    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 org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:278)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    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.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: java.io.FileNotFoundException: class path resource [activiti.cfg.xml] cannot be opened because it does not exist
    at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:172)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:330)
    ... 27 more

I could add activiti.cfg.xml, but it would not be used by my Camunda Spring Boot application. It feels wrong, to add a file to non-testing source only for testing. It would also violate DRY, because I would have to synchronize both configurations.

Is there another way to use ProcessEngineRule in my JUnit test?

dur
  • 15,689
  • 25
  • 79
  • 125

5 Answers5

5

You can instantiate the rule with an engine like this, then Camunda does not try to read from the cfg.xml file:

 @Rule
 public final ProcessEngineRule camunda = new ProcessEngineRule(myConfiguration.buildProcessEngine());

where myConfiguration is an instance of ProcessEngineConfiguration that you create as you like.

If you are using the Spring Boot runner, try importing the camunda-spring-boot-starter-test dependency and use the StandaloneInMemoryTestConfiguration helper for this:

@Rule
public final ProcessEngineRule camunda = new StandaloneInMemoryTestConfiguration().rule();
dur
  • 15,689
  • 25
  • 79
  • 125
Jan Galinski
  • 11,768
  • 8
  • 54
  • 77
  • After passing the engine to `ProcessEngineRule`, the default value of `configurationResource` is set to `"camunda.cfg.xml"` and need this file. how to fix this dependency as you said there is no dependency? – MHSaffari Apr 13 '21 at 05:40
2

Do you use @EnableProcessApplication for your application? If yes, I think you actually don't need org.camunda.bpm.engine.test.ProcessEngineRule any more:

  • You can get the RuntimeService via @Autowired RuntimeService runtimeService;
  • You can get the ProcessEngine via BpmPlatform.getDefaultProcessEngine()

But anyhow, if you really want to use the rule:

Write your own class:

public class MyProcessEngineRule extends ProcessEngineRule {

    @Override
    public Statement apply(Statement base, Description description) {
        // you can use this, if you use AbstractAssertions
        // super.processEngine = AbstractAssertions.processEngine(); 
        super.processEngine = processEngine();
        return super.apply(base, description);
    }

    public static ProcessEngine processEngine() {
        Map<String, ProcessEngine> processEngines = ProcessEngines.getProcessEngines();
        if (processEngines.size() == 1) {
            return processEngines.values().iterator().next();
        } else {
            throw new IllegalStateException("some usefule message");
        }
    }
}

and use @Rule public MyProcessEngineRule rule = new MyProcessEngineRule(); in your testclass.

At least, that worked for me...

markus_
  • 480
  • 3
  • 12
  • This solution only works if you are running a Spring (Boot) test. In a plain Java test Spring is not bootstrapped and hence the process engine needs to be bootstrapped explicitly and autowiring won't be available. – rob2universe Aug 20 '21 at 05:41
  • You are right for the first part of my answer - `@Autowired` only works with spring boot, of course. But you can write and use your own `@Rule` without Spring Boot, as `@Rule` is a JUnit feature. – markus_ Aug 26 '21 at 08:49
  • That's what I mean by bootstrapping the engine explicitly. Apart from Autowiring @EnableProcessApplication also won't do the trick in a plain Java unit test, so the rule is needed. – rob2universe Aug 26 '21 at 11:33
0

The error message is misleading. Camunda is looking for camunda.cfg.xml, but falls back to looking for an activiti.cfg.xml if the file does not exist. This can be fixed in two ways. Either

a) Create a camunda.cfg.xml in src/test/resources.

The content can look like as follows. Adjust plugins list as needed.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="processEngineConfiguration"
          class="org.camunda.bpm.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
        <property name="history" value="full"/>
        <property name="expressionManager">
            <bean class="org.camunda.bpm.engine.test.mock.MockExpressionManager"/>
        </property>
        <property name="processEnginePlugins">
            <list>
                <bean class="org.camunda.connect.plugin.impl.ConnectProcessEnginePlugin"/>
                <bean class="org.camunda.spin.plugin.impl.SpinProcessEnginePlugin"/>
            </list>
        </property>
    </bean>
</beans>

(another example: https://github.com/camunda/camunda-bpm-examples/blob/master/servicetask/rest-service/src/test/resources/camunda.cfg.xml)

or

b) Let your test extend AbstractProcessEngineRuleTest

@Deployment(resources = "process.bpmn")
public class PlainJavaProcessTest extends AbstractProcessEngineRuleTest {

Full example: https://github.com/rob2universe/vanilla-camunda-template/blob/main/src/test/java/com/camunda/example/PlainJavaProcessTest.java

What this class does for you is:

public final ProcessEngineRule processEngine = (new StandaloneInMemoryTestConfiguration(new ProcessEnginePlugin[0])).rule();

c) There are additional options such as those Jan Galinski outlined in his answer

rob2universe
  • 7,059
  • 39
  • 54
0

Below steps worked for me:

  1. Create camunda.cfg.xml in test resource with below content
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean id="processEngineConfiguration"
  class="org.camunda.bpm.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
    <property name="history" value="full"/>
    <property name="processEngineName" value="test-engine"/>
    <property name="expressionManager">
      <bean class="org.camunda.bpm.engine.test.mock.MockExpressionManager"/>
    </property>
  </bean>
</beans>
  1. added below dependency
<dependency>
<groupId>org.camunda.bpm.extension.springboot</groupId>
<artifactId>camunda-bpm-spring-boot-starter-test</artifactId>
<version>2.2.0</version>
</dependency>
c.sankhala
  • 850
  • 13
  • 27
-1

In my case, i am missing connector lib of camunda, added follow libs:

    <dependency>
        <groupId>org.camunda.connect</groupId>
        <artifactId>camunda-connect-connectors-all</artifactId>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.camunda.bpm</groupId>
        <artifactId>camunda-engine-plugin-connect</artifactId>
        <scope>provided</scope>
    </dependency>
duyetpt
  • 1,471
  • 1
  • 10
  • 12