第 12 章 测试业务流程
业务流程可以动态更新,这可能会导致错误,因此测试过程业务也是与任何其他开发工件类似的业务流程生命周期的一部分。
业务流程的单元测试可确保具体用例中过程的行为如预期。例如,您可以基于特定输入测试输出。为了简化单元测试,Red Hat Process Automation Manager 包括 org.jbpm.test.JbpmJUnitBaseTestCase
类。
JbpmJUnitBaseTestCase
作为基础测试案例执行,它用于红帽流程自动化管理器相关测试。JbpmJUnitBaseTestCase
提供以下使用区域:
JUnit 生命周期方法
表 12.1. JUnit 生命周期方法 方法 描述 setUp
此方法标注为
@Before
。它配置数据源和EntityManageronnectionFactoryy
,并删除单例的会话 ID。tearDown
此方法标注为
@After
。它移除了历史、关闭实体管理器
和数据源,并处理RuntimeManager
和RuntimeEngines
。知识库和知识会话管理方法:要创建一个会话,创建
RuntimeManager
和RuntimeEngine
。使用以下方法创建和关闭RuntimeManager
:表 12.2. RuntimeManager 和 RuntimeEngine 管理方法 方法 描述 createRuntimeManager
为给定的资产和选定策略创建
RuntimeManager
。disposeRuntimeManager
在测试范围内激活的
RuntimeManager
。getRuntimeEngine
为给定的上下文创建新的
RuntimeEngine
。断言:要测试资产的状态,请使用以下方法之一:
表 12.3. RuntimeManager 和 RuntimeEngine 管理方法 断言 描述 assertProcessInstanceActive(long processInstanceId, KieSession ksession)
验证具有给定
processInstanceId
的进程实例是否活跃。assertProcessInstanceCompleted(长 processInstanceId)
验证具有给定
processInstanceId
的进程实例是否已完成。如果启用了会话持久性,您可以使用此方法,否则使用assertProcessInstanceNotActive(long processInstanceId, KieSession ksession)
。assertProcessInstanceAborted(长 processInstanceId)
验证具有给定
processInstanceId
的进程实例是否已中止。如果启用了会话持久性,您可以使用此方法,否则使用assertProcessInstanceNotActive(long processInstanceId, KieSession ksession)
。assertNodeExists(ProcessInstance process, String… nodeNames)
验证指定进程是否包含给定的节点。
assertNodeActive(long processInstanceId, KieSession ksession, String… name)
验证具有给定
processInstanceId
的进程实例是否至少包含一个具有指定节点名称的活跃节点。assertNodeTriggered(long processInstanceId, String… nodeNames)
验证在执行指定进程实例的过程中是否为每个给定节点触发节点实例。
assertProcessVarExists(ProcessInstance process, String… processVarNames)
验证给定进程是否包含指定的进程变量。
assertProcessNameEquals(ProcessInstance process, String name)
验证给定名称是否与指定进程名称匹配。
assertVersionEquals(ProcessInstance process, String version)
验证给定进程版本是否与指定进程版本匹配。
帮助程序方法:使用以下方法为具有或不使用持久性的给定进程集合创建新的
RuntimeManager
和RuntimeEngine
。有关持久性的更多信息,请参阅 Red Hat Process Automation Manager 中的进程引擎。表 12.4. RuntimeManager 和 RuntimeEngine 管理方法 方法 描述 setupPoolingDataSource
配置数据源。
getDs
返回配置的数据源。
getEmf
返回配置的
实体管理器onnectionFactoryy
。getTestWorkItemHandler
返回除了默认的工作项处理程序之外可以注册的测试工作项处理程序。
clearHistory
清除历史记录日志。
以下示例包含一个起始事件、脚本任务和结束事件。JUnit 测试示例会创建一个新的会话,并启动 hello.bpmn
进程,并验证进程实例是否已完成,以及 StartProcess
、Hello
和 EndProcess
节点是否已执行。
图 12.1. hello.bpmn
进程的 JUnit 测试示例
public class ProcessPersistenceTest extends JbpmJUnitBaseTestCase { public ProcessPersistenceTest() { super(true, true); } @Test public void testProcess() { createRuntimeManager("hello.bpmn"); RuntimeEngine runtimeEngine = getRuntimeEngine(); KieSession ksession = runtimeEngine.getKieSession(); ProcessInstance processInstance = ksession.startProcess("com.sample.bpmn.hello"); assertProcessInstanceNotActive(processInstance.getId(), ksession); assertNodeTriggered(processInstance.getId(), "StartProcess", "Hello", "EndProcess"); } }
JbpmJUnitBaseTestCase
支持所有预定义的 RuntimeManager
策略,作为单元测试的一部分。因此,在创建一个 RuntimeManager 作为单个测试的一部分,它足以指定创建 RuntimeManager
时使用的策略。以下示例演示了在任务服务中使用 PerProcessInstance 策略来管理用户任务:
public class ProcessHumanTaskTest extends JbpmJUnitBaseTestCase { private static final Logger logger = LoggerFactory.getLogger(ProcessHumanTaskTest.class); public ProcessHumanTaskTest() { super(true, false); } @Test public void testProcessProcessInstanceStrategy() { RuntimeManager manager = createRuntimeManager(Strategy.PROCESS_INSTANCE, "manager", "humantask.bpmn"); RuntimeEngine runtimeEngine = getRuntimeEngine(ProcessInstanceIdContext.get()); KieSession ksession = runtimeEngine.getKieSession(); TaskService taskService = runtimeEngine.getTaskService(); int ksessionID = ksession.getId(); ProcessInstance processInstance = ksession.startProcess("com.sample.bpmn.hello"); assertProcessInstanceActive(processInstance.getId(), ksession); assertNodeTriggered(processInstance.getId(), "Start", "Task 1"); manager.disposeRuntimeEngine(runtimeEngine); runtimeEngine = getRuntimeEngine(ProcessInstanceIdContext.get(processInstance.getId())); ksession = runtimeEngine.getKieSession(); taskService = runtimeEngine.getTaskService(); assertEquals(ksessionID, ksession.getId()); // let John execute Task 1 List<TaskSummary> list = taskService.getTasksAssignedAsPotentialOwner("john", "en-UK"); TaskSummary task = list.get(0); logger.info("John is executing task {}", task.getName()); taskService.start(task.getId(), "john"); taskService.complete(task.getId(), "john", null); assertNodeTriggered(processInstance.getId(), "Task 2"); // let Mary execute Task 2 list = taskService.getTasksAssignedAsPotentialOwner("mary", "en-UK"); task = list.get(0); logger.info("Mary is executing task {}", task.getName()); taskService.start(task.getId(), "mary"); taskService.complete(task.getId(), "mary", null); assertNodeTriggered(processInstance.getId(), "End"); assertProcessInstanceNotActive(processInstance.getId(), ksession); } }
12.1. 测试与外部服务集成
业务流程通常包括调用外部服务。业务流程的单元测试允许您注册测试处理程序,以验证是否正确请求特定服务,并为请求的服务提供测试响应。
要测试与外部服务的交互,请使用 default TestWorkItemHandler
处理程序。您可以注册 TestWorkItemHandler
,以收集特定类型的所有工作项目。另外 ,testWorkItemHandler
包含与任务相关的数据。工作项目代表一个工作单元,如发送特定电子邮件或调用特定服务。TestWorkItemHandler
会在执行过程中验证是否请求特定的工作项,以及相关的数据是否正确。
以下示例演示了如何验证电子邮件任务以及是否收到电子邮件是否引发异常。单元测试使用请求电子邮件时执行的测试处理器,可让您测试与电子邮件相关的数据,如发件人和接收者。在 abortWorkItem()
方法通知引擎电子邮件发送失败后,单元测试将通过生成错误并记录操作来验证进程是否处理此类情况。在这种情况下,进程实例最终会被中止。
图 12.2. 电子邮件进程示例
public void testProcess2() { createRuntimeManager("sample-process.bpmn"); RuntimeEngine runtimeEngine = getRuntimeEngine(); KieSession ksession = runtimeEngine.getKieSession(); TestWorkItemHandler testHandler = getTestWorkItemHandler(); ksession.getWorkItemManager().registerWorkItemHandler("Email", testHandler); ProcessInstance processInstance = ksession.startProcess("com.sample.bpmn.hello2"); assertProcessInstanceActive(processInstance.getId(), ksession); assertNodeTriggered(processInstance.getId(), "StartProcess", "Email"); WorkItem workItem = testHandler.getWorkItem(); assertNotNull(workItem); assertEquals("Email", workItem.getName()); assertEquals("me@mail.com", workItem.getParameter("From")); assertEquals("you@mail.com", workItem.getParameter("To")); ksession.getWorkItemManager().abortWorkItem(workItem.getId()); assertProcessInstanceNotActive(processInstance.getId(), ksession); assertNodeTriggered(processInstance.getId(), "Gateway", "Failed", "Error"); }