An Introduction to Business Process Testing using JProcessUnit
Pages: 1, 2, 3

Creating the Utility methods

I begin by creating a method that starts off instances of my process:

private void startTimeOffProcess(String timeOffRequestXML) {



    // Create the start event

    startProcessTimeOffRequest = new StartProcessEvent(SERVICE_URI_PREFIX,

            IS_PROCESSTIMEOFFREQUEST_JPD);

    startProcessTimeOffRequest.setSoapMessage(timeOffRequestXML);



    // Add an undo event to terminate the process

    TerminateProcessEvent terminateProcess = new TerminateProcessEvent(

            startProcessTimeOffRequest);

    this.addUndoEvent(terminateProcess);



    // Assert event and give the process time to get started and running

    startProcessTimeOffRequest.assertEvent();

    waitForProcess(1000);

}

As you can see, I begin by creating a StartProcessEvent instance with information relating to the parent JPD of the process called ProcessTimeOffRequest.jpd. I proceed by creating a TerminateProcessEvent for the same JPD and set it as an undo event. This will ensure that regardless of the success or failure of my test, an attempt will be made to terminate the JPD instance created by the StartProcessEvent.

With this utility method created, I can move on to the creation of a utility method for the next section of my process: the execution of the IsTimeOffFeasible.jpd that calls a Web service to an illusionary HR system (in this case the Web service always returns true) to verify the feasibility of the requested time off:

private void assertFeasibility() {



    // Create a wait even for the IsTimeOffFeasible child JPD.

    String isFeasibleId = startProcessTimeOffRequest

            .getInstanceID(SERVICE_URI_PREFIX + "/" + IS_TIMEOFFFEASIBLE_JPD);

    ProcessStateWaitEvent completeWaitEvent = new ProcessStateWaitEvent(

                isFeasibleId, ProcessStatus.COMPLETED);



    // Create a terminate undo event for this JPD

    TerminateProcessEvent terminateProcess = new TerminateProcessEvent(

        SERVICE_URI_PREFIX + "/" + IS_TIMEOFFFEASIBLE_JPD, isFeasibleId);

    this.addUndoEvent(terminateProcess);



    // Wait until the child JPD has completed execution

    completeWaitEvent.assertEvent();



    // Check that the request was feasible through an internal variable.

    String isFeasible = startProcessTimeOffRequest.getStringVariableValue(

                SERVICE_URI_PREFIX + "/" + IS_TIMEOFFFEASIBLE_JPD,

                FEASIBLE_VAR_NAME);

    assertEquals(isFeasible, "true");

}

This method first creates a ProcessStateWaitEvent instance to verify the completion of the (child) IsTimeOffFeasible.jpd instance. Before I assert this event, I create an undo event that can terminate the child instance JPD. After successfully asserting that the IsTimeOffFeasible.jpd has completed, I can then retrieve the value of an internal variable to check the result returned from the HR system and make sure that it is set to true.

I am now ready to move on to the creation of a utility method for the testing of the time off approval by the supervisor:

private void completeTimeOffApprovalTask(boolean approved) {



    // The process creates a task for the supervisor with the employee ID

    // field. We create a selector for this task to use for all task events.

    TaskSelector selector = new TaskSelector();

    selector.setTaskName(SUPERVISOR_TASK_NAME, false);



    // Wait until the supervisor task is created

    TaskWaitEvent taskCheck = new TaskWaitEvent(selector);

    taskCheck.assertEvent();



    // Create an undo task to make sure that the task is deleted

    DeleteTaskEvent deleteTask = new DeleteTaskEvent(selector);

    this.addUndoEvent(deleteTask);



    // Complete task with an approval response.

    CompleteTaskEvent approveRequest = new CompleteTaskEvent(selector);

    approveRequest.setTaskResponse(createApprovalResponseXML(approved).toString());

    approveRequest.assertEvent();

}

This method verifies the creation, completion, and result of the WebLogic Integration worklist task associated with my process. This task is created by the process for the employee's supervisor to obtain approval (or denial) for the time-off request. I begin this method by instantiating a TaskWaitEvent class to verify the creation of the supervisor task. Once I have successfully verified the creation of this task, I create a DeleteTaskEvent event instance and set it as an undo event. I end the method by instantiating a CompleteTaskEvent object. This action event allows me to effectively simulate the completion of the task by a person (in this case the supervisor) through a worklist user interface.

The final utility method that I look at is used to verify the successful response of the time off process:

private void verifyProcessReturn(boolean approval) {



    // Wait until the process returns with a response

    ReturnProcessWaitEvent timeOffResponse = new ReturnProcessWaitEvent(

                RESPONSE_METHOD_NAME, startProcessTimeOffRequest);

    timeOffResponse.assertEvent();



    // Compare returned response to the expected response

    XmlObject actualResponse = timeOffResponse.getResponseContent();

    XmlObject expectedResponse = createApprovalResponseXML(approval);



    assertEquals(expectedResponse.toString(), actualResponse.toString());

}

I can do this by instantiating a ReturnProcessWaitEvent object with the name of the response node that I am concerned with (the name used for the JPD's Client Response node method) and the StartProcessEvent object used to start the process. Once I know that the process successfully responded, I can retrieve its response message through the getResponseContent() method and verify its content accordingly. In this case, I do this by building an expected response (approval or denial) based on the utility method's parameter and comparing it with the actual response message from the process.

I have now created utility methods for the verification of the nodes involved in the two execution paths that I would like to create test cases for.

Configuration of the test environment

Before running any test cases, the JProcessUnit environment must be configured so it can interact with the appropriate WebLogic Integration server instance that is hosting our target JPDs. This is done by modifying the JProcessUnitConfig.xml file and making sure it is in the JUnit project's class path. Detailed instructions on the configuration of this file as well the addition of other required JAR files to the testing environment can be found within the JProcessUnit download package documentation and they are therefore not repeated here. Once you have finished this configuration, you are ready to run your tests in your favorite JUnit execution environment.

Thoughts on Testing

Now that I have introduced the JProcessUnit framework and you are ready to start writing some of your own test cases, I would like you to keep the following in mind.

First, it is important to highlight the fact that JProcessUnit provides a black box testing approach. JProcessUnit tests exercise the functionality of a process from its outward-facing interfaces. This is rather similar to a testing framework such as HttpUnit where, instead of a business process, a user interface is being tested from the user's point of view.

Black box testing of a system's outward interfaces is important (for a detailed analysis of the reasons for this, see this interesting article.) The creation and maintenance of such tests, however, can be more involved, and this is no exception for JProcessUnit. As such, the creation of tests for every single execution path of every process may not be a cost-effective approach. In most cases, therefore, it is more reasonable to write a small number of test cases for each process that test the main paths of executions. These tests can then be used for simple regression to ensure the system's sanity as changes occur.

Second, it should be noted that, as it stands, the JProcessUnit framework is by no means complete. The framework is, of course, expected to undergo improvements as the needs arise, with new features and required design changes. Most importantly, although the current set of events is sufficient to perform the essential interactions with JPDs, some key elements, such as events for the testing of dynamic message broker subscriptions, are still missing and need to be implemented. The set of process test events that the current API contains hopefully will grow in time, as the users of the framework start writing their own test events that are better tailored for their immediate needs.

Finally, as you may have noticed by now, the testing techniques discussed so far should apply to the testing of any type of automated business processes running within any Business Process Engine (BPE) and not only to WebLogic Integration JPDs. This is due to the fact that the core design of the JProcessUnit API does not make any assumption about the underlying business process engine technology at play. Instead, the API can be extended with technology-specific ActionEvent and WaitEvent subclasses. The current version of JProcessUnit contains two different types of such extensions: a set of BPE neutral events for simple, generic File and Database process interactions, and a set of WebLogic Integration-specific events, for interactions with JPDs, that I have covered in this article.

Download

You can download the full source code for JProcessUnit from the CodeShare project.

You can also download JProcessUnitExample.zip, the complete example application described in this article.

Summary

In this article I introduced the JProcessUnit CodeShare project, which allows the creation of JUnit-based automated tests for business processes and, more specifically, WebLogic Integration Java Process Definitions. The article explained the benefits of creating automated tests for JPDs and provided a walkthrough for the creation of such tests using JProcessUnit.

References

Reza Shafii works for BEA Systems professional services.