使用 MockitoJUnitRunner 和 SpringRunner 进行 camunda 单元测试
Posted
技术标签:
【中文标题】使用 MockitoJUnitRunner 和 SpringRunner 进行 camunda 单元测试【英文标题】:camunda unit testing with MockitoJUnitRunner and SpringRunner 【发布时间】:2022-01-18 19:56:37 【问题描述】:我正在为 Camunda 工作流程编写测试用例。我正在使用 SpringRunner @RunWith(SpringRunner.class)
并在测试执行所需的测试类中具有以下属性
@Autowired
private ProcessEngine processEngine;
@Rule
@ClassRule
public static ProcessEngineRule rule;
@PostConstruct
void initRule()
rule = TestCoverageProcessEngineRuleBuilder.create(processEngine).withDetailedCoverageLogging().build();
@Mock
ProcessScenario someProcessScenario;
此外,在每个测试中,我都会像这样实例化 ProcessInstance
ProcessRunner.ExecutableRunner.StartingByStarter starter = Scenario.run(someProcessScenario)
.startBy(() ->
processInstance = rule.getRuntimeService().startProcessInstanceByKey("PROCESS_DEFINITION", properties);
return processInstance;
);
starter.engine(rule.getProcessEngine());
此配置工作正常,我使用 BpmnAwareTests 断言并且所有测试都通过了。我在 pom 中使用的依赖项是
<dependency>
<groupId>org.camunda.bpm.assert</groupId>
<artifactId>camunda-bpm-assert</artifactId>
<version>5.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.camunda.bpm.extension</groupId>
<artifactId>camunda-bpm-assert-scenario</artifactId>
<version>1.1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.camunda.bpm.extension</groupId>
<artifactId>camunda-bpm-process-test-coverage</artifactId>
<version>0.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.camunda.bpm.extension.mockito</groupId>
<artifactId>camunda-bpm-mockito</artifactId>
<scope>test</scope>
<version>4.12.0</version>
</dependency>
由于这个设置为每个测试类实例化了 spring 容器,我想改变几个类来运行 MockitoJUnitRunner 而不是 SpringRunner。
所以我把那些改成@RunWith(MockitoJUnitRunner.class)
并像这样初始化所需的属性:
@Rule
public ProcessEngineRule rule = new ProcessEngineRule();
@Mock
ApplicationEventPublisher eventPublisher;
@Mock
ProcessScenario someOtherProcess;
@Mock
SomeClass someclass;
@Before
public void setUp() throws MyCustomiException
MockitoAnnotations.openMocks(this);
MyDelegate myDelegate = new MyDelegate(someclass);
Mocks.register("myDelegate", myDelegate);
......
ProcessInstance 在上面的所有测试用例中都被实例化。 这些测试也可以顺利运行并独立通过。 但是,当我运行所有测试(一些使用 SpringRunner 和其他使用 MockitoJUnitRunner 运行)时,它们没有通过。 SpringRunner 的所有测试都失败了,在 SpringRunner 之后执行的测试也失败了。 错误是 java.lang.IllegalStateException: No ProcessEngine found to be registered with ProcessEngines!
【问题讨论】:
【参考方案1】:您混淆了两个测试概念:通过 spring 的集成测试和通过规则的单元测试。 Spring Boot 测试将根据您的 yaml 和 bean 配置配置流程引擎,并且(通常)运行大部分应用程序(数据库、消息传递......)。 使用该规则的单元测试在使用内存引擎(使用内存数据库)时效果最佳。
总结:在你的spring boot测试中,不要使用ProcessEngineRule,使用你的app配置的引擎。在你的纯流程单元测试中,不要使用弹簧,通过 MockExpressionManager 连接所有内容。
【讨论】:
【参考方案2】:我发现进行单元测试的一个好方法是使用“隐藏的”引擎配置,当您只有一个引擎规则而没有其他基于弹簧的上下文时,它总是会被查找。 这可以通过简单地将 camunda.cfg.xml 添加到您的测试资源来完成,如下所示:
<?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.extension.process_test_coverage.junit.rules.ProcessCoverageInMemProcessEngineConfiguration">
<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="" />
<!-- Database configurations -->
<property name="databaseSchemaUpdate" value="true" />
<!-- job executor configurations -->
<property name="jobExecutorActivate" value="false" />
<property name="history" value="full" />
</bean>
</beans>
请注意,这使用了流程覆盖引擎配置,您可以查找 here。但您可以使用任何其他配置。
一旦你有了这个引擎配置,你就可以像这样简单地创建一个单元测试:
@Deployment(resources = "myBpmFile.bpmn")
public class ApplicationTest
private static final String PROCESS_DEFINITION_KEY = "myProcessDefinitionKey";
@Rule
@ClassRule
public static ProcessEngineRule rule = TestCoverageProcessEngineRuleBuilder.create().build();
private RuntimeService runtimeService;
@Before
public void setup()
runtimeService = rule.getRuntimeService();
registerJavaDelegateMock(MyDelegate.class)
//register more mocks
@Test
public void testHappyPath()
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(PROCESS_DEFINITION_KEY);
assertThat(processInstance).isActive();
assertThat(processInstance).hasPassed("MyServiceTask");
verifyJavaDelegateMock(MyDelegate.class).executed();
assertThat(processInstance).isWaitingAtExactly("MyUserTask");
complete(task());
assertThat(processInstance).isEnded();
请注意,这里使用camunda-bpm-mockito 和camunda-bpm-assert。 绝对值得研究一下,因为它使您的测试轻量级、快速、定义明确且易于阅读。
作为额外的奖励,测试覆盖率 EngineRule 将为您提供有价值的覆盖率图表(html 格式)并允许基于百分比的覆盖率断言。
编辑:这是针对 JUnit4 的。您也可以使用 JUnit 5 来做到这一点。
【讨论】:
以上是关于使用 MockitoJUnitRunner 和 SpringRunner 进行 camunda 单元测试的主要内容,如果未能解决你的问题,请参考以下文章
PowerMockRunner和ActiveObjectsJUnitRunner