Since developing process oriented software is no different from developing any other software, we believe that process definitions should be easily testable. This chapter shows how you can use plain JUnit without any extensions to unit test the process definitions that you author.
The development cycle should be kept as short as possible. Changes made to the sources of software should be immediately verifiable. Preferably, without any intermediate build steps. The examples given below will show you how to develop and test jBPM processes without intermediate steps.
Mostly the unit tests of process definitions are execution scenarios. Each scenario is executed in one JUnit testmethod and will feed in the external triggers (read: signals) into a process execution and verifies after each signal if the process is in the expected state.
Let's look at an example of such a test. We take a simplified version of the auction process with the following graphical representation:
Now, let's write a test that executes the main scenario:
public class AuctionTest extends TestCase { // parse the process definition static ProcessDefinition auctionProcess = ProcessDefinition.parseParResource("org/jbpm/tdd/auction.par"); // get the nodes for easy asserting static StartState start = auctionProcess.getStartState(); static State auction = (State) auctionProcess.getNode("auction"); static EndState end = (EndState) auctionProcess.getNode("end"); // the process instance ProcessInstance processInstance; // the main path of execution Token token; public void setUp() { // create a new process instance for the given process definition processInstance = new ProcessInstance(auctionProcess); // the main path of execution is the root token token = processInstance.getRootToken(); } public void testMainScenario() { // after process instance creation, the main path of // execution is positioned in the start state. assertSame(start, token.getNode()); token.signal(); // after the signal, the main path of execution has // moved to the auction state assertSame(auction, token.getNode()); token.signal(); // after the signal, the main path of execution has // moved to the end state and the process has ended assertSame(end, token.getNode()); assertTrue(processInstance.hasEnded()); } }
Before you can start writing execution scenario's, you need a ProcessDefinition. The easiest way to get a ProcessDefinition object is by parsing xml. If you have code completion, type ProcessDefinition.parse and activate code completion. Then you get the various parsing methods. There are basically 3 ways to write xml that can be parsed to a ProcessDefinition object:
A process archive is a zip file that contains the process xml in a file called processdefinition.xml. The jBPM process designer reads and writes process archives. For example:
... static ProcessDefinition auctionProcess = ProcessDefinition.parseParResource("org/jbpm/tdd/auction.par"); ...
In other situations, you might want to write the processdefinition.xml file by hand and later package the zip file with e.g. an ant script. In that case, you can use the JpdlXmlReader
... static ProcessDefinition auctionProcess = ProcessDefinition.parseXmlResource("org/jbpm/tdd/auction.xml"); ...
The simplest option is to parse the xml in the unit test inline from a plain String.
... static ProcessDefinition auctionProcess = ProcessDefinition.parseXmlString( "<process-definition>" + " <start-state name='start'>" + " <transition to='auction'/>" + " </start-state>" + " <state name='auction'>" + " <transition to='end'/>" + " </state>" + " <end-state name='end'/>" + "</process-definition>"); ...