Friday, March 23, 2012

BPEL - Unit test

Oracle SOA Suite 11g provides a testing framework to support
• Define tests, assertions, and emulations using JDeveloper
• Run these tests either from the EM console or on the command line using ANT
• Review the test results from the EM console or as a JUnit report


Three parts to a test case
1. Initiation defines the service and operation invoked along with the test data.
2. Emulation defines the message or fault returned from a reference or component invoked through a synchronous response or a callback without executing the component or referenced service.
3. Assertion compares the message or part of the message over an SCA wire against the expected data.



A test includes definitions of the initiation, emulations, and assertions. The test suite is a part of the composite project and is deployed along with the composite to the server and can be initiated from the EM console.

Creating the unit test

1. In the Application navigator of JDeveloper, expand the SOA Content folder and right-click on the test suites folder and select Create Test Suite.

2. Name the test suite and click on OK.

3. Right click on tests folder and select Create Test.

4. Name the test and click on OK. The unit test design view will display. It has slightly difference with the composite view. The swim lanes on the left and right are yellow.

    (NOTE: By selecting the Return to SOA composite diagram button at the top of the window, you can return to the normal composite editor.)

5. Create initiate message by right click on the binding component.
In the Initiate Messages window, you can click on Generate Sample to generate a sample request. After that, you can save the sample data as a xml file by Save As. Then, we can choose Load From File radio button to use the saved file.
Click on OK. After closing the dialog, you will see a blue arrow on the inbound component indicating that there is a message set for that service.

6. Double-click on the wire between BPEL process and the web service reference.
Select the Emulates tab and click on the plus sign.
In the Create Emulate window, you can generate a sample and save as a file. Then you can choose load from file.
Click on OK.
Click on OK again. After closing the dialog, notice that the wire has changed to a dashed line and there is an arrow indicating there is a message set for the return value of that service.

7. Double-click on the wire between BPEL process and the web service client interface.

  Add an assertion by selecting the green plus sign.
On the popup window, select Assert Output. Like the previous steps, you can generate a sample and save as a file and then select Load From File.
After everything is done, the view will look like the follow.

After you put correct testing data, you can deploy the application to SOA server and test it from EM.

8. Log into the EM and select the service. Select the Unit Tests tab on the right side and select the test case you want to run and click Execute button.
After execution, you can see the result on Test Run tab of Unit Tests.

In the creation of Unit Test, you need to be very careful to handle the naming spaces of XML. If the naming space is not correct, you may run into some stranger scenario.

In the Emulation, there are Emulate Output, Emulate Callback (used for asynchronized webservice) and Emulate Fault (used for a webservice with fault).
In the Assertion, there are Assert Input, Assert Output, Assert Callback and Assert Fault. You can choose different Assert Target by clicking on Browse button.
In the Select Assert Target window, you can select any element listed in the payload.

At last, if you have a web service without fault definition in the wsdl, you will not be able to use Assert Fault and it is not testable in the unit test. Currently, it is a constrain of SOA unit test framework.

Sometimes, maybe you runs a timeout when you run a test case. The reason maybe just the returned response is not what you want to assert. As there isn't matched response, the test runs timed out.

NOTE:
If you want to assert a request and response in XML fragment, you have to put the namespace properly, otherwise the assertions will be failed. You can find these error from the execution result and find out what the difference is between real result and expected result.

OSB - Design Time Considerations

(From http://www.art2dec.com/documentation/docs/fmw11g1114documentation/core.1111/e10108/osb.htm)


Design Time Considerations for Proxy Applications

Consider the following design configurations for proxy applications based on your OSB usage and use case scenarios:
  • Avoid creating many OSB context variables that are used just once within another XQuery
    Context variables created using an Assign action are converted to XmlBeans and then reverted to the native XQuery format for the next XQuery. Multiple "Assign" actions can be collapsed into a single Assign action using a FLWOR expression. Intermediate values can be created using "let" statements. Avoiding redundant context variable creation eliminates overheads associated with internal data format conversions. This benefit has to be balanced against visibility of the code and reuse of the variables.
  • Transforming contents of a context variable such as $body.
    Use a Replace action to complete the transformation in a single step. If the entire content of $body is to be replaced, leave the XPath field blank and select "Replace node contents". This is faster than pointing to the child node of $body (e.g. $body/Order) and selecting "Replace entire node". Leaving the XPath field blank eliminates an extra XQuery evaluation.
  • Use $body/*[1] to represent the contents of $body as an input to a Transformation (XQuery / XSLT) resource.
    OSB treats "$body/*[1]" as a special XPath that can be evaluated without invoking the XQuery engine. This is faster than specifying an absolute path pointing to the child of $body. A general XPath like "$body/Order" must be evaluated by the XQuery engine before the primary transformation resource is executed.
  • Enable Streaming for pure Content-Based Routing scenarios.
    Read-only scenarios such as Content-Based Routing can derive better performance from enabling streaming. OSB leverages the partial parsing capabilities of the XQuery engine when streaming is used in conjunction with indexed XPaths. Thus, the payload is parsed and processed only to the field referred to in the XPath. Other than partial parsing, an additional benefit for read-only scenarios is that streaming eliminates the overhead associated with parsing and serialization of XmlBeans.
    The gains from streaming can be negated if the payload is accessed a large number of times for reading multiple fields. If all fields read are located in a single subsection of the XML document, a hybrid approach provides the best performance. (See "Design Considerations for XQuery Tuning" for additional details.)
    The output of a transformation is stored in a compressed buffer format either in memory or on disk. Therefore, streaming should be avoided when running out of memory is not a concern.
  • Set the appropriate QOS level and transaction settings.
    Do not set XA or Exactly-Once unless the reliability level required is once and only once and its possible to use the setting (it is not possible if the client is a HTTP client). If OSB initiates a transaction, it is possible to replace XA with LLR to achieve the same level of reliability.
    OSB can invoke a back end HTTP service asynchronously if the QOS is "Best- Effort". Asynchronous invocation allows OSB to scale better with long running back-end services. It also allows Publish over HTTP to be truly fire-and-forget.
  • Disable or delete all log actions.
    Log actions add an I/O overhead. Logging also involves an XQuery evaluation which can be expensive. Writing to a single device (resource or directory) can also result in lock contentions.


Design Considerations for XQuery Tuning

OSB uses XQuery and XPath extensively for various actions like Assign, Replace, and Routing Table. The following XML structure ($body) is used to explain XQuery and XPath tuning concepts:
<soap-env:Body>
<Order>
<CtrlArea>
<CustName>Mary</CustName>
</CtrlArea>
<ItemList>
<Item name="ACE_Car" >20000 </Item>
<Item name=" Ext_Warranty" >1500</Item>
…. a large number of items
</ItemList>
<Summary>
<Total>70000</Total>
<Status>Shipped</Status>
<Shipping>My Shipping Firm </Shipping>
</Summary>
</Order>
</soap-env:Body>
  • Avoid the use of double front slashes ("//") in XPaths.
    $body//CustName while returning the same value as $body/Order/CtrlArea/CustName will perform a lot worse than the latter expression. "//" implies all occurrences of a node irrespective of the location in an XML tree. Thus, the entire depth and breadth of the XML tree has to be searched for the pattern specified after a "//". Use "//" only if the exact location of a node is not known at design time.
  • Index XPaths where applicable.
    An XPath can be indexed by simply adding "[1]" after each node of the path. XQuery is a declarative language and an XPath can return more than one node; it can return an array of nodes. $body/Order/CtrlArea/CustName implies returning all instances Order under $body and all instances of CtrlArea under Order. Therefore, the entire document has to be read in order to correctly process the above XPath. If you know that there is a single instance of Order under $body and a single instance of CtrlArea under Order, we could rewrite the above XPath as $body/Order[1]/CtrlArea[1]/CustName[1].
    The second XPath implies returning the first instances of the child nodes. Thus, only the top part of the document needs to be processed by the XQuery engine resulting in better performance. Indexing is key to processing only what is needed.
    Note:
    Indexing should not be used when the expected return value is an array of nodes. For example, $body/Order[1]/ItemList[1]/Item returns all "Item" nodes, but $body/Order[1]/ItemList[1]/Item[1] only returns the first item node. Another example is an XPath used to split a document in a "for" action.
  • Extract frequently used parts of a large XML document as intermediate variables within a FLWOR expression
    An intermediate variable can be used to store the common context for multiple values. Sample XPaths with common context:
    $body/Order[1]/Summary[1]/Total, $body/Order[1]/Summary[1]/Status,$body/Order[1]/Summary[1]/Shipping
    
    The above XPaths can be changed to use an intermediate variable:
    let $summary := $body/Order[1]/Summary[1]
    $summary/Total, $ summary/Status, $summary/Shipping
    
    Using intermediate variables consumes more memory but reduces redundant XPath processing.
  • Using a Hybrid Approach for read-only scenarios with Streaming
    The gains from streaming can be negated if the payload is accessed a large number of times for reading multiple fields. If all fields read are located in a single subsection of the XML document, a hybrid approach provides the best performance. The hybrid approach includes enabling streaming at the proxy level and Assigning the relevant subsection to a context variable, The individual fields can then be accessed from this context variable.
    The fields "Total" and "Status" can be retrieved using three Assign actions:
    Assign "$body/Order[1]/Summary[1]" to "foo"
    Assign "$foo/Total" to "total"
    Assign "$foo/Status" to "total"