Show Table of Contents
11.14. Testing Business Processes
11.14.1. Unit Testing
You must design business processes at a high level with no implementation details. You must ensure that they are tested as they also have a lifecycle like other development artifacts and can be updated dynamically.
Unit tests are conducted to ensure processes behave as expected in specific use cases, for example, to test the output based on the specific input. The helper class
JbpmJUnitTestCase (in the jbpm-test module) has been included to simplify unit testing. JbpmJUnitTestCase provides the following:
- Helper methods to create a new knowledge base and session for a given set of processes.
- Assert statements to check:
- The state of a process instance (active, completed, aborted).
- Which node instances are currently active.
- Which nodes have been triggered (to check the path that has been followed).
- The value of variables.
The image below contains a start event, a script task, and an end event. Within the example junit Test, a new session is created, the process is started, and the process instance is verified based on successful completion. It also checks whether these three nodes have been executed.

Figure 11.2. Example Hello World Process
Example 11.2. example junit Test
public class ProcessPersistenceTest extends JbpmJUnitBaseTestCase {
public ProcessPersistenceTest() {
// setup data source, enable persistence
super(true, true);
}
@Test
public void testProcess() {
// create runtime manager with single process - hello.bpmn
createRuntimeManager("hello.bpmn");
// take RuntimeManager to work with process engine
RuntimeEngine runtimeEngine = getRuntimeEngine();
// get access to KieSession instance
KieSession ksession = runtimeEngine.getKieSession();
// start process
ProcessInstance processInstance = ksession.startProcess("com.sample.bpmn.hello");
// check whether the process instance has completed successfully
assertProcessInstanceCompleted(processInstance.getId(), ksession);
// check what nodes have been triggered
assertNodeTriggered(processInstance.getId(), "StartProcess", "Hello", "EndProcess");
}
}
}
The
JbpmJUnitBaseTestCase method acts as base test case class that you can use for JBoss BPM Suite related tests. It provides four usage areas:
- JUnit life cycle methods:
setUp: This method is executed @Before. It configures data source and EntityManagerFactory and cleans up Singleton's session idtearDown: This method is executed @After. It clears out history, closes EntityManagerFactory and data source and disposes RuntimeEngines and RuntimeManager
- Knowledge Base and KnowledgeSession management methods:
createRuntimeManager: This method creates RuntimeManager for given set of assets and selected strategy.disposeRuntimeManager: This method disposes RuntimeManager currently active in the scope of test.getRuntimeEngine: This method creates new RuntimeEngine for given context.
- Assertions:
assertProcessInstanceCompletedassertProcessInstanceAbortedassertProcessInstanceActiveassertNodeActiveassertNodeTriggeredassertProcessVarExistsassertNodeExistsassertVersionEqualsassertProcessNameEquals
- Helper methods:
getDs: This method returns currently configured data source.getEmf: This method returns currently configured EntityManagerFactory.getTestWorkItemHandler: This method returns test work item handler that might be registered in addition to what is registered by default.clearHistory: This method clears history log.setupPoolingDataSource: This method sets up data source.
JbpmJUnitBaseTestCase supports all the predefined RuntimeManager strategies as part of the unit testing. It is enough to specify which strategy shall be used whenever creating runtime manager as part of single test. The following example uses PerProcessInstance runtime manager strategy and task service to deal with 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");
assertProcessInstanceCompleted(processInstance.getId(), ksession);
}
}11.14.2. Testing Integration with External Services
Using domain-specific processes makes it possible to use testing handlers to verify whether or not specific services are requested correctly.
A
TestWorkItemHandler is provided by default that can be registered to collect all work items (each work item represents one unit of work, for example, sending q specific email or invoking q specific service, and it contains all the data related to that task) for a given type. The test handler can be queried during unit testing to check whether specific work was actually requested during the execution of the process and that the data associated with the work was correct.
The following example describes how a process that sends an email could be tested. The test case tests whether an exception is raised when the email could not be sent (which is simulated by notifying the engine that sending the email could not be completed). The test case uses a test handler that simply registers when an email was requested and the data associated with the request. When the engine is notified the email could not be sent (using
abortWorkItem(..)), the unit test verifies that the process handles this case successfully by logging this and generating an error, which aborts the process instance in this case.

public void testProcess2() {
// create runtime manager with single process - hello.bpmn
createRuntimeManager("sample-process.bpmn");
// take RuntimeManager to work with process engine
RuntimeEngine runtimeEngine = getRuntimeEngine();
// get access to KieSession instance
KieSession ksession = runtimeEngine.getKieSession();
// register a test handler for "Email"
TestWorkItemHandler testHandler = getTestWorkItemHandler();
ksession.getWorkItemManager().registerWorkItemHandler("Email", testHandler);
// start the process
ProcessInstance processInstance = ksession.startProcess("com.sample.bpmn.hello2");
assertProcessInstanceActive(processInstance.getId(), ksession);
assertNodeTriggered(processInstance.getId(), "StartProcess", "Email");
// check whether the email has been requested
WorkItem workItem = testHandler.getWorkItem();
assertNotNull(workItem);
assertEquals("Email", workItem.getName());
assertEquals("me@mail.com", workItem.getParameter("From"));
assertEquals("you@mail.com", workItem.getParameter("To"));
// notify the engine the email has been sent
ksession.getWorkItemManager().abortWorkItem(workItem.getId());
assertProcessInstanceAborted(processInstance.getId(), ksession);
assertNodeTriggered(processInstance.getId(), "Gateway", "Failed", "Error");
}11.14.3. Configuring Persistence
You can configure whether you want to execute the JUnit tests using persistence or not. By default, the JUnit tests will use persistence, meaning that the state of all process instances will be stored in a (in-memory H2) database (which is started by the JUnit test during setup) and a history log will be used to check assertions related to execution history. When persistence is not used, process instances will only live in memory and an in-memory logger is used for history assertions.
Persistence (and setup of data source) is controlled by the super constructor and allows following:
default: This is the no argument constructor and the most simple test case configuration (does NOT initialize data source and does NOT configure session persistence). It is usually used for in memory process management, without human task interactionsuper(boolean, boolean): This allows to explicitly configure persistence and data source. This is the most common way of bootstrapping test cases for JBoss BPM Suite.super(true, false): To execute with in-memory process management with human tasks persistence.super(true, true): To execute with persistent process management with human tasks persistence
super(boolean, boolean, string): This is same as super(boolean, boolean), however it allows use of another persistence unit name than default (org.jbpm.persistence.jpa).
Here is an example:
public class ProcessHumanTaskTest extends JbpmJUnitBaseTestCase {
private static final Logger logger = LoggerFactory.getLogger(ProcessHumanTaskTest.class);
public ProcessHumanTaskTest() {
// configure this tests to not use persistence for process engine but still use it for human tasks
super(true, false);
}
}
Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.