测试整个过程路径
测试整个过程路径
为什么要测试流程模型?简短的答案是:从技术角度来看,BPMN是一种编程语言。因此,图应被视为代码。
我们将逐步介绍最佳做法和步骤,以简化测试,并仔细查看许多可用的库,包括:
- camunda-bpm-assert
- camunda-bpm-assert场景
- camunda-bpm-mockito
- camunda-bpm-jgiven
- flowcov-camunda
- camunda-bpm-process-test-coverage
在测试模型时,您可能会遇到以下问题:
- 何时以及如何使用这些不同的库?
- 究竟应该测试什么–模型和/或执行的代码?
- 如何处理对其他模型的依赖性?
- 如何衡量我的考试覆盖率?
我们将主要关注第一个测试范围并使用Java编写单元测试。
今天的主题是:测试整个流程路径
让我们看一下以下订单履行过程:
“整个过程路径”表示从头到尾进行测试。对于复杂的模型,我们经常看到测试用例仅覆盖某些部分。在我们的流程中,一个示例是分别测试订单取消。您可能要采用此方法的原因是,之前和之后的序列已经过测试,或者各个测试用例变得更大且修改起来更复杂。
但是,您应该始终测试整个过程路径,以确保:
- 考虑到过程中的依赖关系:对之前或之后执行的元素进行更改可能会产生副作用。对于处理所需的变量更改尤其如此。
- 测试用例的定义得到简化:乍一看,这听起来是矛盾的。但是我们发现,考虑整个流程场景可以简化测试用例的定义。特别是在仅考虑替代方案中活动和数据的不同行为时。
- 过程中的调整变得更加容易:因为考虑了整个过程,所以可以更加确定地对过程进行调整。
但是,在某些情况下,测试流程的各个活动是有意义的。一个示例是可重用组件。例如,任务“发送取消”可以是用于发送电子邮件的可重用服务任务。但是,它不仅应在订单履行过程中进行测试,而且还应在单独的范围内进行测试。
使用camunda-bpm-assert库,可以非常轻松地测试这些小的可重用组件。但是,测试更复杂的过程会导致冗余或不清楚的代码。因此,camunda-bpm-assert-scenario可用于测试整个过程路径。
定义默认行为:首先,为所有元素定义默认行为。这也适用于不在“快乐道路”上的任务,例如“取消订单”任务。这意味着在各个方案中仅需要指定行为差异。
@Before
public void defaultScenario() {
MockitoAnnotations.initMocks(this);
Mocks.register("sendCancellationDelegate", new SendCancellationDelegate());
//Happy-Path
when(testOrderProcess.waitsAtUserTask(TASK_CHECK_AVAILABILITY))
.thenReturn(task -> {
task.complete(withVariables(VAR_PRODUCTS_AVAILABLE, true));
});
when(testOrderProcess.waitsAtUserTask(TASK_PREPARE_ORDER))
.thenReturn(TaskDelegate::complete);
when(testOrderProcess.waitsAtUserTask(TASK_DELIVER_ORDER))
.thenReturn(task -> {
task.complete(withVariables(VAR_ORDER_DELIVERED, true));
});
//Further Activities
when(testOrderProcess.waitsAtUserTask(TASK_CANCEL_ORDER))
.thenReturn(TaskDelegate::complete);
}
标识具有不同输出的活动:此步骤是关于标识提供替代输出的活动,以便该过程根据输出采用不同的路径。这些活动通常位于“包含”或“专用”网关之前。在我们的示例中,这适用于两个任务。
“交付订单”活动甚至还有两个附加方案。
- 订单无法成功交付,第二天将重试
- 无法交货,必须取消订单。
在确定了不同的场景之后,现在可以实施特定的测试用例。
实施测试用例:为了使实施尽可能简单,仅考虑与流程相关的变量。
为此,您仅需启动场景。之后,可以检查某些元素或结束事件是否已完成。
@Test
public void shouldExecuteHappyPath() {
Scenario.run(testOrderProcess)
.startByKey(PROCESS_KEY)
.execute();
verify(testOrderProcess)
.hasFinished(END_EVENT_ORDER_FULLFILLED);
}
发送取消
我们需要覆盖“检查可用性”任务的行为:
@Test
public void shouldExecuteCancellationSent() {
when(testOrderProcess.waitsAtUserTask(TASK_CHECK_AVAILABILITY)).thenReturn(task -> {
task.complete(withVariables(VAR_PRODUCTS_AVAILABLE, false));
});
Scenario.run(testOrderProcess)
.startByKey(PROCESS_KEY)
.execute();
verify(testOrderProcess)
.hasFinished(END_EVENT_CANCELLATION_SENT);
}
取消订单
为了测试这一点,我们需要在“交付订单”任务中抛出错误而不是完成它:
@Test
public void shouldExecuteOrderCancelled() {
when(testOrderProcess.waitsAtUserTask(TASK_DELIVER_ORDER)).thenReturn(task -> {
taskService().handleBpmnError(task.getId(), "OrderCancelled");
});
Scenario.run(testOrderProcess)
.startByKey(PROCESS_KEY)
.execute();
verify(testOrderProcess)
.hasCompleted(TASK_CANCEL_ORDER);
verify(testOrderProcess)
.hasFinished(END_EVENT_ORDER_CANCELLED);
}
两次交付
要使用计时器事件执行循环,然后完成该过程,我们需要为“交付订单”任务定义两种不同的方案:
@Test
public void shouldExecuteDeliverTwice() {
when(testOrderProcess.waitsAtUserTask(TASK_DELIVER_ORDER)).thenReturn(task -> {
task.complete(withVariables(VAR_ORDER_DELIVERED, false));
}, task -> {
task.complete(withVariables(VAR_ORDER_DELIVERED, true));
});
Scenario.run(testOrderProcess)
.startByKey(PROCESS_KEY)
.execute();
verify(testOrderProcess, times(2))
.hasCompleted(TASK_DELIVER_ORDER);
verify(testOrderProcess)
.hasFinished(END_EVENT_ORDER_FULLFILLED);
}
相关教程
- 2020-10-23
- 2020-10-22
- 2020-10-22
- 2020-10-22
- 2020-10-22
- 2020-10-22
- 2020-10-22
- 2020-10-21
- 2020-10-19
- 2020-10-15