Chapter 12. Testing a business process
A business process can be updated dynamically, which can cause errors, therefore testing a process business is also a part of the business process life cycle similar to any other development artifact.
The unit test for a business process ensures that the process behaves as expected in a specific use case. For example, you can test an output based on a particular input. To simplify unit testing, Red Hat Process Automation Manager includes the org.jbpm.test.JbpmJUnitBaseTestCase
class.
The JbpmJUnitBaseTestCase
performs as a base test case class, which is used for Red Hat Process Automation Manager related tests. The JbpmJUnitBaseTestCase
provides the following usage areas:
JUnit life cycle methods
Table 12.1. JUnit life cycle methods Method Description setUp
This method is annotated as
@Before
. It configures a data source andEntityManagerFactory
and deletes the session ID of a singleton.tearDown
This method is annotated as
@After
. It removes history, closesEntityManagerFactory
and a data source, and disposesRuntimeManager
andRuntimeEngines
.Knowledge base and knowledge session management methods: To create a session, create
RuntimeManager
andRuntimeEngine
. Use the following methods to create and disposeRuntimeManager
:Table 12.2. RuntimeManager and RuntimeEngine management methods Method Description createRuntimeManager
Creates
RuntimeManager
for a given set of assets and selected strategy.disposeRuntimeManager
Disposes
RuntimeManager
that is active in the scope of the test.getRuntimeEngine
Creates new
RuntimeEngine
for the given context.Assertions: To test the state of assets, use the following methods:
Table 12.3. RuntimeManager and RuntimeEngine Management Methods Assertion Description assertProcessInstanceActive(long processInstanceId, KieSession ksession)
Verifies whether a process instance with the given
processInstanceId
is active.assertProcessInstanceCompleted(long processInstanceId)
Verifies whether a process instance with the given
processInstanceId
is completed. You can use this method if session persistence is enabled, otherwise useassertProcessInstanceNotActive(long processInstanceId, KieSession ksession)
.assertProcessInstanceAborted(long processInstanceId)
Verifies whether a process instance with the given
processInstanceId
is aborted. You can use this method if session persistence is enabled, otherwise useassertProcessInstanceNotActive(long processInstanceId, KieSession ksession)
.assertNodeExists(ProcessInstance process, String… nodeNames)
Verifies whether the specified process contains the given nodes.
assertNodeActive(long processInstanceId, KieSession ksession, String… name)
Verifies whether a process instance with the given
processInstanceId
contains at least one active node with the specified node names.assertNodeTriggered(long processInstanceId, String… nodeNames)
Verifies whether a node instance is triggered for each given node during the execution of the specified process instance.
assertProcessVarExists(ProcessInstance process, String… processVarNames)
Verifies whether the given process contains the specified process variables.
assertProcessNameEquals(ProcessInstance process, String name)
Verifies whether the given name matches the specified process name.
assertVersionEquals(ProcessInstance process, String version)
Verifies whether the given process version matches the specified process version.
Helper methods: Use following methods to create a new
RuntimeManager
andRuntimeEngine
for a given set of processes with or without using persistence. For more information about persistence, see Process engine in Red Hat Process Automation Manager.Table 12.4. RuntimeManager and RuntimeEngine Management Methods Method Description setupPoolingDataSource
Configures a data source.
getDs
Returns the configured data source.
getEmf
Returns the configured
EntityManagerFactory
.getTestWorkItemHandler
Returns a test work item handler that can be registered in addition to the default work item handler.
clearHistory
Clears the history log.
The following example contains a start event, a script task, and an end event. The example JUnit test creates a new session, starts the hello.bpmn
process, and verifies whether the process instance is completed and the StartProcess
, Hello
, and EndProcess
nodes are executed.
Figure 12.1. Example JUnit Test of hello.bpmn
Process
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
supports all predefined RuntimeManager
strategies as part of the unit testing. Therefore, it is enough to specify the strategy that is used when you create a RuntimeManager
as part of a single test. The following example shows the use of the PerProcessInstance strategy in a task service to manage user tasks:
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. Testing integration with external services
Business processes often include the invocation of external services. Unit testing of a business process enables you to register test handlers that verify whether the specific services are requested correctly, and also provide test responses for the requested services.
To test the interaction with external services, use the default TestWorkItemHandler
handler. You can register the TestWorkItemHandler
to collect all the work items of a particular type. Also, TestWorkItemHandler
contains data related to a task. A work item represents one unit of work, such as sending a specific email or invoking a specific service. The TestWorkItemHandler
verifies whether a specific work item is requested during an execution of a process, and the associated data is correct.
The following example shows how to verify an email task and whether an exception is raised if the email is not sent. The unit test uses a test handler that is executed when an email is requested and enables you to test the data related to the email, such as the sender and recipient. Once the abortWorkItem()
method notifies the engine about the email delivery failure, the unit test verifies that the process handles such case by generating an error and logging the action. In this case, the process instance is eventually aborted.
Figure 12.2. Example email process
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"); }