Service Oriented Architecture (SOA) presents unique challenges to software testing. In a normal Object Oriented Programming (OOP), a developer is usually responsible for:
- Testing a component that is sufficiently coarse grained. Such as facade Session EJB or a model layer Java class. This can be automated through JUnit. WebSphere Integration Developer offers a EJB test client which requires manual data entry. Here, the goal is to test a component without waiting for a consumer of the component (usually a web application or GUI client of some sort) to be developed.
- Testing a feature of the application from an end user point of view. This re-tests the components mentioned above. However, this time, the view layer (GUI) is tested in conjunction with the model layer.
In SOA, the components that make up an application are:
- Business processes
- Services that are invoked from the processes. WebSphere Process Server allows a service to be implemented as a web service, a Java class, business rule, human task or state machine.
- Interface maps and data maps used by the interface maps.
A challenge with SOA based software development is that various components may be developed by different teams possibly from different organizations. SOA involves contract based development. That is, each component must adhere to the interface agreed between parties. It is expected that as long as the components adhere to the agreed interfaces, everything will work fine once they are composed together in a business process. Different teams can have different schedules. It is difficult for one team to affect the project management of another team. So, it is essential that each component is tested well in isolation as the window of opportunity to test the software with all components working together may be small.
A component may depend on other components. Such as:
- A business process invokes many service operations.
- An interface map has reference to a source and target interface.
How can you unit test a component when some of the dependent components have not been developed? This is where the emulator feature of WID comes into play. During testing of a component, when the component invokes an operation of another component that has not been implemented yet, WID allows you to manually view the input data sent to the operation and enter output data. You can also create more advanced automated emulators.
The focus of this tutorial is testing. We do not want to spend too much time actually developing a SOA based application. This tutorial tests various components of the PropagateProductAvailability business process developed in a previous tutorial. It is recommended that you go through that tutorial to get an understanding for the application. You can also download and import the solution available as a project interchange format. In that case, deploy the SimpleModuleApp to the process server and test the PropagateProductAvailability process as outlined in that tutorial.
Before you proceed, make sure that the server has started and the PropagateProductAvailability process is working properly.
UNIT TEST THE SERVICE
In this step, we will learn how to test a service in isolation. We will test the AcmeProductManagement service that is implemented in the com.acme.services.AcmeProductManagementImpl class. A service that is implemented as a web service can also be tested this way.
Open the assembly editor. Right click on AcmeProductManagement and select Test Component. System opens the test client.
The AcmeProductManagement component should be automatically selected. The component implements only one interface – AcmeProductManagement. Hence, that interface should be automatically selected. The interface has only one operation – addNewProduct. Hence, the operation is automatically selected. You can always select a different interface or method.
Below the interface and operation selection area, you will the request parameter data entry area. Each row in the table represents an input parameter to the operation.
Enter some values as shown above. Click on the Continue button. After a while, you should see the output from the service in the Console view.
SystemOut O Received new product notification from: WEB AGE SystemOut O Product ID: 1234
Congratulations. You just tested a service in isolation from a business process.
LEARN TO USE DATA POOL
Manually entering data during testing can be time consuming and error prone. Carefully entering data that mimics certain scenarios (such as invalid data or products out of inventory) can be even more difficult. WID allows you to save the input data in a data pool. You can later select data from the pool any time you need to enter data.
Right click on the product row in the request parameter table and select Add Value to Pool. Enter Light Bulb as the name of the data.
Now, close the test client without saving. Re-open the test client by right clicking on AcmeProductManagement and selecting Test Component.
In the request parameter table, right click on the product row and select Use Value From Pool.
System automatically filters the data pool by the AcmeProduct type. Select the row containing the Light Bulb data. Then click on OK. Notice, how system fills in the data for the product input parameter.
You can manage the data pool. Just click on the Data Pool button. System will open the data pool editor. You can change the name of the data (Light Bulb) and any of the values. You can right click on the main row for a data and select Remove Value. You can click on Update to make the changes permanent. Note: You can not add new data from the data pool editor.
UNIT TESTING AN INTERFACE MAP
Unit testing an interface map also tests the data maps that are used by the interface map. There is no other way to test a data map.
An interface map has a source and target interface. When you unit test the map in isolation, you will need to manually emulate both. That is, you will need to enter the input data for the source operation and enter the output data for the target operation.
The ProductMaintenance_To_AcmeProductManagement interface map is already added to the assembly diagram. (Otherwise, you will need to drag and drop it on the diagram). Right click on the interface map and select Test Component. The source interface for the map is ProductMaintenance. This interface should be automatically selected in the test client. The interface has only one method – notifyNewProduct. This should be also selected by default. If an interface has several methods, you will need to select the method you will like to test.
Enter some input values as shown above. Then click on Continue. The target interface for the map is AcmeProductManagement. The notifyNewProduct operation of the ProductMaintenance interface is mapped to the addNewProduct operation of the AcmeProductManagement interface. System will halt testing at the manual emulator for the addNewProduct operation. System shows the input data that is coming to the addNewProduct operation after interface and data mapping has been applied.
Notice that the manufacturerID parameter has been supplied by the interface map. The data map used by the interface map has also converted the Product object to AcmeProduct object. Notice, how the short and long description has been merged into the Description field. Also, the map has supplied the value for the Currency field.
The addNewProduct does not have any output data. Hence the Output parameters table area is disabled. Otherwise, you could enter simulated output values there. Click on Continue to submit the emulated output values of the addNewProduct method. This will also complete the unit testing of the map.
Close the test client without saving it.
UNIT TEST A BUSINESS PROCESS
A process can be tested in three different ways.
- Test the process an the services that are invoked by the process. The test client will provide manual emulators for reference partners that are not yet wired to an actual service implementation. This testing comes closest to testing the way the process will actually run when deployed in production.
- Test the process only and provide manual emulation for all services that are invoked by the process. In this mode, system provides and emulator even if a reference partner has been wired to an implementation. This type of testing can be useful, if a service implementation is temporarily unavailable or showing buggy behavior. In that case, it is safer to test the process in full emulation mode rather than break the wiring.
- Test a fully completed process that has been deployed in a server. This test can be done in a test machine or production machine where WID is not installed. This tests a fully completed process in isolation for a GUI client that starts the process.
We have already learned how to test a process completely (mode 1) in previous tutorials. Essentially, you right click on a white area of the assembly diagram and select Test Module. Then you select the business process component, interface and the method that starts the process. We will not describe this process here.
To test a process in full emulation mode (mode 2), right click on the process component (PropagateProductAvailability) in the assembly editor and select Test Component. The test client will automatically select the correct component, interface and start method. You can enter some input values and click on Continue. The reference partner acmeDealer of the process is wired to the ProductMaintenance_To_AcmeProductManagement interface map component. System will halt at a manual emulator for the map. You can view the input data that is coming to the method of the source interface. If that method returned any output data, you could enter that in the Output parameters table.
Click on Continue to end the test.
Now, we will test the process without using the test client. This type of testing can be done entirely using a web browser in a machine where WID is not installed. You can test a process that has been deployed in a production or test server. Right click on the process server instance in the Servers view and select Launch->BPC Explorer. (Alternatively, open a browser and enter the URL http://localhost:9080/bpc/).
Wait for the initial screen to show up. Then, click on My Process Templates. This will show all the business processes that have been deployed to the server. Select the checkbox next to the PropagateProductAvailability process. Then click on the Start Instance button.
System will provide a screen to enter input values to the operation that starts the process.
Enter some values as shown above. (Note: the Process Name field is optional. It sets the name of the instance that is about to be created. If you do not enter a value, system will assign a name by default. If you are running a test in the production system, you may wish to enter a name to distinguish it from the actual process instances started by the users).
Click on Submit. You should see the following output in the Console view (or SystemOut.log file in a production system).
SystemOut O Announcing new product: PR1234 SystemOut O Short description: Light bulb. SystemOut O Received new product notification from: 000001 SystemOut O Product ID: PR1234
In SOA, each building block needs to be tested individually. This will identify defects and architectural problems early on. If you wait for the all the pieces to be tied together before you start testing, the cost of fixing a defect may be prohibitive. In this tutorial we learned how to test various components as follows.
- Test a service implementation in isolation for a process that invokes it.
- Test an interface map in isolation from a business process or actual implementation of the interfaces. This also tests the data maps used by the interface map. Data maps can not be tested in isolation.
- Test a business process in three different ways.
We also learned how to save input test data in the Data Pool. This speeds up unit test and makes it less error prone.