Skip to main content

skip to main content

developerWorks  >  Lotus  >

Designing composite applications: Unit testing

developerWorks
Document options

Document options requiring JavaScript are not displayed

Discuss


Rate this page

Help us improve this content


Level: Intermediate

Craig Wolpert (cwolpert@us.ibm.com), Senior Software Engineer, IBM
Jo Grant (jo_grant@us.ibm.com), Senior Software Engineer, IBM

05 Feb 2008
Updated 27 Jun 2008

The ease with which users can assemble composite applications from components increases the need to unit test your components before users use them. This article, fourth in our series on composite applications, describes how to test your components prior to assembling composite applications.

Editor's note: This article is the fourth in a series of articles on composite applications to be published on developerWorks Lotus over the next few months. See the previous developerWorks articles, "Designing composite applications: Design patterns," "Designing composite applications: Component design," and "The Lead Manager application in IBM Lotus Notes V8: An Overview."

About this article series

Composite applications are a key element in a Service-Oriented Architecture (SOA) and contextual collaboration strategy. They support business flexibility for companies and organizations that must rapidly respond to changing demands in today's competitive markets. Composite applications are aggregations of user interface components that are loosely coupled to support intercomponent communication.

Components can be reused in multiple composite applications. The ability to combine multiple technologies into a single application provides significant business value. It enables companies to protect and extend their existing assets with increasing degrees of flexibility, and it allows them to respond quickly and cost effectively to their emerging business requirements with applications that are significantly easier to create than multiple application development environments.

This loose coupling of the composite application architecture also enables diverse groups in different locations to leverage each others' efforts and to interoperate with each other. For example, one department may be working on the accounting application for a company, while another group is working on a sales lead tracking application. The composite application vision is to add to the accounting application some components from the sales lead tracking application to give pertinent views of assets in an accounting context. Similarly, the sales lead tracking application could incorporate components from the accounting application to give accounting information within an asset context. As your company develops more and more composite applications, the potential for integration increases exponentially. The goal is that the whole is greater than the sum of the parts.

The composition application model is already familiar to IBM WebSphere Portal developers. This approach has been extended to IBM Lotus Notes V8, enabling Lotus Notes developers to surface their Lotus Notes applications as one or more components in a composite application. IBM Lotus Domino Designer has been extended to leverage the property broker and to provide a more intuitive user environment. Lotus Notes V8 also supports the inclusion of Eclipse components. A composite application may have any combination of Lotus Notes and Eclipse components. These components may be presented together in the same user interface (UI) for on-the-glass integration, or if extended to use the property broker, they can fully interoperate. You can define composite applications using the Composite Application Editor or the WebSphere Portal Application Template Editor.

The development of components for composite applications is different from traditional Eclipse or Lotus Notes application development. It is highly desirable to create components that are flexible enough to be deployed in composite applications at later dates without significant rework.



Back to top


Prerequisites

This article assumes that you are familiar with composite applications in IBM Lotus Notes, so it may be useful for you to review the introduction to the composite application section in the IBM Lotus Domino Designer help.

You should then review the developerWorks Lotus articles, "Designing composite applications: Design patterns," "Designing composite applications: Component design," and "The Lead Manager application in IBM Lotus Notes V8: An Overview," which cover component design from a high level. They discuss domain-centric components and contextual domain components, which are meta-patterns in and of themselves.



Back to top


Unit testing

The creation of composite applications differs from traditional application development in one important way: The development effort occurs in two stages. First, components are written, and then later are assembled into applications. This approach has several advantages. Because components can be reused in multiple ways, you optimize your effort with a "build once, use many" approach. Second, the task of assembling components is not as technical as building components, so a broader mix of people can be involved in the process. As a result, application development is brought closer to the end user, which yields application designs that build more upon domain expert knowledge.

With these advantages, though, come concerns that must be addressed. Because components are not custom built for specific uses, you must attempt to anticipate all scenarios. Because composite applications are being assembled later in the process by less technical people, components must behave consistently and predictably. Components should also have good documentation describing the valid values to pass to their interfaces.

One essential approach to ensure the successful development and deployment of components is unit testing. If the components are guaranteed to work well before they are deployed, there will be fewer problems and less frustration in the field when they are put together, providing a better and more cost-effective experience for all.



Back to top


General approach

Because components don't interoperate at a code level, traditional methods of unit testing are not necessarily appropriate. Certainly, if the components simply surface lower-level business logic, that business logic is best tested programmatically. LotusScript libraries can do this for Lotus Notes code, and the JUnit module for Eclipse is quite good for Java code. But for the components themselves, the best way to test them is within the environment for which they are built, that is, a composite application.

The key approach in this article revolves around creating and using a test component. Quite simply, this is a component that has properties and actions of each data type used anywhere in any of your component development. These properties and actions are paired and connected with the UI. When an action is set on the test component, a corresponding part of the UI is filled with the value it receives. This value can be changed or edited by the operator, a Set button can be pressed, and when this is done, a property is fired off with the current value in the Edit field.

This test component is then deployed in a composite application with one -- and only one -- other component, and that is the component under test. Every property that the component under test publishes is wired to an action on the test component corresponding to the type of that property. Every action that the component under test consumes has a property on the test component of the corresponding type wired to it. In this way, every time any property on the component under test changes value, it can be seen by the operator immediately. The operator can also exercise any action in the component under test by filling in a value in the test component and clicking its Set button.

A test script can now be written and run with this test application to exercise the component under test. The script contains instructions on which actions to perform in the component under test and what results are expected in the test component to track properties being fired. It also contains instructions on appropriate values to enter for actions and what the expected reaction is in the UI. This way, all the functionality of the component can be exercised, valid behavior asserted, boundary conditions explored, and graceful degrading ensured.

In some cases, it may be preferable to test multiple components in a unit-test composite application. In that case, you should test each component in isolation first before combining components to perform integration testing.



Back to top


Developing the test component

The test component may be implemented either in Eclipse or in Lotus Notes both of which we discuss here. Because the component communicates on the property broker level, it does not matter which, so simply select the architecture with which you are most familiar.

The first step is common to both components. You need to create a Web Services Description Language (WSDL) file declaring the properties and actions that your test component uses. First, survey the other components that you use. Collect from them the namespaces and data type that they use. Plan on having at least one property and one action for each unique type. If you have many properties of a single type, or if you envisage a test case in which you may want to distinguish between multiple actions or properties of a single type, just create multiple entries for that in your test component.

If we examine the properties and actions declared by the standard Lotus Notes components, we find the following types:

Namespace: http://com.ibm.propertybroker.standardtypes

Types:

  • emailAddress
  • canonicalName
  • commonName
  • NotesURL
  • MailTo
  • toField

Namespace: http://w3.ibm.com/xmlns/ibmww/sw/datatype

Types:

  • secondaryDateList

Namespace: http://www.w3.org/2001/XMLSchema

Types:

  • string

NOTE: There are also some types based on the datetime format, but we cover only simple string types in this article.

Based on this, we create a single property and action for each of the custom types, and we create three properties and actions for the generic string type called Misc1, Misc2, and Misc3. Note that all property names are prefixed with get, such as getEmailAddress, and all action names with set, such as setEmailAddress.

You can create the WSDL file by using the Property Broker Editor that comes with Lotus Notes, the WSDL Editor that comes with Eclipse or IBM Rational Application Developer for WebSphere Software, or manually. One approach is to start with a WSDL file from one of your components, extend this until it has all the required types, and then replace the properties and actions with the new ones.

The WSDL file we use for this example is in the Downloads section.



Back to top


Developing a Lotus Notes test component

The easiest way to create a test component in Lotus Notes is to create a Lotus Notes component (database) that contains a single Lotus Notes component view. We create an STTester.nsf file based on a blank template, and for ease of access, we import our common property broker routines into a LotusScript library. An implementation of these routines is included in the Lotus Sandbox sample, Lead Manager composite application sample for IBM Lotus Notes 8, in the PBRoutines Script Library. We then add a single form called ST Tester.

In the main area of the form, we create a table with one row for each property and action pair we defined, one column for a label, another for an Edit field, and a last one for a Set button. The fields are named after the base property action to which they corresponded. For this, we have EmailAddress and so on.

We instrument each Set button to publish the value of its corresponding field to the property broker. Listing 1 shows a simple script to do this.


Listing 1. Set button code
                
Sub Click(Source As Button)
	Const PropName = "EmailAddress"
	Dim workspace As New NotesUIWorkspace
	Dim uidoc As NotesUIDocument
	Dim PropValue As String
	Set uidoc = workspace.CurrentDocument
	PropValue = uidoc.FieldGetText( PropName )
	publishProperty "get"+PropName, PropValue
End Sub

Because we plan to cut and paste this script into each Set button and because the only difference between them is the property name, we declare this in a constant at the top of the script. After pasting, we just need to make a single change in that one place. The rest of the script is quite straightforward; we get the current value from the field in the document, and then publish it to the property broker.

For each value, we define a Lotus Notes action. In the properties box for the Lotus Notes action, we map it to the corresponding property broker action defined in the WSDL file. The body of the action is a similarly simple script as shown in listing 2.


Listing 2. Defining a Lotus Notes action
                
Sub Click(Source As Button)
	Const PropName = "EmailAddress"
	Dim workspace As New NotesUIWorkspace
	Dim uidoc As NotesUIDocument
	Dim PropValue As String
	Set uidoc = workspace.CurrentDocument
	PropValue = getActionParameter()
	uidoc.FieldSetText PropName, PropValue
End Sub

The only difference here is that we receive the passed-in value from the property broker action and assign it to the field to which it corresponds. Last, we recommend that you create an invisible SaveOptions computed text field with a value of zero. Choose Create - Field to add a text field named SaveOptions to your form as follows:

  1. Use the field's properties box to specify that it is a computed field.
  2. Select the programmers pane for the SaveOptions field, and set the value to "0". Be sure to include the quotation marks around the zero character.
  3. Click SaveOptions in the work pane, and double-click to open the properties box for the field.
  4. On the sixth tab (window-shade graphic) of the properties box, in the Hide paragraph from selection field, select Notes R4.6 or later.

This prevents the system from prompting you to save the form when it is closed. When it is complete, you can add this component to your palette, and then to a composite application.

NOTE: We strongly recommend that you create a unit test for your unit test component (see figure 1). This may seem a little redundant, but unit testing applies just as much to the tools with which you are testing as to what you are testing.


Figure 1. STTester Form component



Back to top


Developing an Eclipse test component

The sources for the Eclipse test component, Standard Types Tester (see figure 2), can be found on the OpenNTF.Org Web site and follow along the lines of a typical Eclipse-based component as is used in many of the components in the Component Library. The sources are included as an attachment to Help - About this Application. A plug-in is created to house the component, the WSDL file is added, and the basic classes of the view, the data model, and the action handler are created and referenced in extension points.

To do this, in the data model, create a field for each property/action pair. Then expose these through set and get accessor functions, making sure that the set functions publish their changes to the property change support mechanism. This is how the helper libraries know when to publish a property.


Figure 2. Standard Types Tester

When creating the view, normally for paired properties and actions you want information to be chained. When an action is set, the corresponding property is called, allowing for much flexibility in the way a component is wired. In this case, though, we want to deliberately separate how a component receives and sends properties. Otherwise, we can't be sure of propagation, and being able to know exactly what happens is essential for testing.

Instead of creating a single data model for the view, we create two. One is tied to incoming actions, and the other is tied to outgoing properties. We attach a listener to the incoming data model, and when it is notified of a change, it reads the value from the incoming data model and writes it into the UI field. For the other direction, we attach a listener to the Set button. When pressed, it reads the current value of the UI field and writes it into the output data model. This is linked using the libraries to broadcast the property changes.

For the whole component, refer to Composite Application Component Library on OpenNTF.org. Below are some excerpts showing where things differ from the standard model. First, we declare two data models instead of one as shown in listing 3.


Listing 3. Declaring two data models
                
    private STTesterViewBean    mDataIn;
    private STTesterViewBean    mDataOut;
    
    public STTesterView() {
        mDataIn = new STTesterViewBean();
        mDataOut = new STTesterViewBean();
    }

The output model is registered with a PBBroadcast() helper object. This ensures that changes to it are broadcast as property changes:

new PBBroadcast(this, mDataOut, "http://com.ibm.propertybroker.standardtypes,
http://w3.ibm.com/xmlns/ibmww/sw/datatype,http://www.w3.org/2001/XMLSchema");

The input model is referenced in the getData() method required by the abstract IDataProvider interface in the helper library, ensuring that actions received are written to the input data model:

public PCSBean getData() {
return mDataIn;
}

A helper function is created to add each line to the display as shown in listing 4.


Listing 4. Adding the helper function
                
    	addLine(client, "EmailAddress");
	...
    private void addLine(Composite client, String name) {
        GridUtils.makeLabel(client, makeLabelName(name), "");
        Text input = GridUtils.makeText(client, (String)null, "fill=h");
        mDataIn.addPropertyChangeListener(makePropertyName(name), new DoInput(input));
        Button go = GridUtils.makeButton(client, "Set", "");
        go.addSelectionListener(new DoOutput(input, name));
    }

This helper function creates the label, the input field, and the Set button for each property/action pair. It also creates the needed listener to listen to the input data model and to propagate changes from it to the UI field. In addition, it creates another listener to listen to the Set button, which, when clicked, publishes the value of the UI field to the output data model as shown in listing 5.


Listing 5. Creating listeners
                
    class DoInput implements PropertyChangeListener {
		...
		public void propertyChange(PropertyChangeEvent ev) {
			mControl.setText(ev.getNewValue().toString());			
		}
    }

    class DoOutput implements SelectionListener {
		...
		public void widgetSelected(SelectionEvent ev) {
			String newVal = mControl.getText();
			PBHandler.setValue(mDataOut, "set"+mProperty, newVal);			
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error:  The previous line is longer than the max of 90 characters ---------|
		}
    }

As with the Lotus Notes implementation, when complete, you can add this component to your palette, and then create a unit test for it.



Back to top


Creating a unit test plan

Every component should have a specification detailing which properties it publishes under which conditions, which actions it consumes, which values are valid for those actions, and what it does when it consumes such an action. This is discussed in the developerWorks article, "Designing composite applications: Component design." A good test plan addresses and validates each of those areas. If there is a good specification, it is easy to write a good test plan.

The tester component can be instrumental in validating the test plan, although typically a component is deployed with an array of other components and linked up to propagate business logic, which does not make a good test environment. You cannot create specific circumstances, and because you are testing more than one thing at a time, confusion can arise over which part is failing.

Instead, we recommend that you create a simple composite application containing only the component under test and the tester component. Wire each property in the component under test to a valid action in the test component. For each valid action in the component under test, ensure that a wire is created to it from the tester component. Once each component is unit tested, it is easier to assemble and wire the components in the application. Test components are never final; they should be updated as components change.

For Lotus Notes component views, properties and actions are scoped to the component (database), not the component view (form, frameset, or view), so properties and actions may appear where there are not valid values for that component. The specification for the component view should delineate which of those properties and actions are valid for that component. Because a user may wire the wrong things, you should consider adding tests for invalid properties and actions to ensure that the component degrades gracefully and that no unexpected side effects emerge.

Your test plan then becomes a walk-through with the following checklist:

  1. Positive testing

    • UI gestures. For each UI gesture defined in the specification, create a line in your unit test. Ask the operator to make this gesture, and then check the result in the test component. Did the expected properties publish?
    • Action handling. For each supported action, ask the operator to fill in values in the test component, and then click the Set button. Did the UI change as expected? If this was also designed to trigger further property firings, did that happen?
  2. Negative testing

    • UI gestures. Consider all the other things a user might do with the UI, such as clicking the wrong points or entering invalid values, accented characters, or unusual characters. Create a line for each. Ask the operator to make the gesture, and determine if properties fire that should not.
    • Action handling. For each supported action, devise all the wrong ways to fill it in, such as blank, very large strings, ill-formatted data, or accented or unusual characters. Create a line for each with sample text to be cut and pasted into the UI. Click the Set button, and examine the component to see if it behaves acceptably.
    • Action handling. For each unsupported action, come up with a reasonable variety of values to fill in and set. Ensure that the component ignores them.

NOTE: Although you can create these test composite applications and use them for your test cycle, you can also have them created on the fly during your development. They don't take much time to make, and they may identify problems with deployment and distribution that would otherwise be hard to find.

Table 1 shows an example of a test plan that you may write for testing the Lotus Notes Contacts view. You can write your notes on this plan as you work.


Table 1. Example test plan for Lotus Notes Contacts view
Test
Test setup
Create a new composite application, TestNotesContactView.nsf.
In Composite Application Editor (CAE), add the NotesContactsView on the top and a Standard Types Tester on the bottom.
Open the wiring tool on the NotesContactView component.
Wire as follows:
Notes URL changed - Notes URL
Common name changed - Misc 1
Email address changed - Misc 2
Street address changed - Misc 3
Save and open the wiring tool on the Standard Types Tester component.
Ensure there are no actions displayed on the NotesContactView component.
Exit CAE.
Open names.nsf, and ensure the correct data set is loaded. Close it.
Test execution
Open the TestNotesContactView.nsf application and ensure that no properties fire and that the last selected letter page is shown.
Select letter W from the left navigator and ensure that:
W-last names show
The first one, Mis Wajda, is selected
In the tester, Misc1 is Wajda, Mis
In the tester, Misc 2 is MisWajda@llama.ibm.com
Select letter X from the left navigator and ensure that no names show and that no properties change.

Figure 3 shows the test component with which you might use this test plan.


Figure 3. Example test component



Back to top


Beyond unit testing

This structure and system have uses beyond simple component validation. No testing is perfect, and complicated situations can occur in the field that you cannot anticipate. The typical developer's nightmare is a problem in a simple component occurring in a complicated application. With a system like this, however, you can examine the log files and use other debugging options to attempt to recreate the inputs to the component that caused the fault. These values can be fed back into the component at fault using the unit test composite application. With luck, you can recreate the fault in the unit test and diagnose it without having to load the full, complicated environment. Of course, after you recreate the fault, the instructions for doing so make an excellent addition to the unit test script so that you can catch regressions in future releases.



Back to top


Conclusion

This article provides a solid foundation for developing unit tests and shows how they benefit composite applications by allowing each component to be tested. We have developed and executed unit testing while developing the Lead Manager composite application sample and believe it is a useful addition to the process because it makes it easier to realize the benefit of reusable components in composite applications.



Resources

Learn

Get products and technologies

Discuss


About the authors

Craig Wolpert is a Senior Software Engineer for the IBM Lotus Software ISV Technical Enablement program.


Jo Grant is a Senior Software Engineer for IBM Lotus, specializing in Eclipse-based technology.




Rate this page


Please take a moment to complete this form to help us better serve you.



 


 


Not
useful
Extremely
useful
 


Share this....

digg Digg this story del.icio.us del.icio.us Slashdot Slashdot it!



Back to top