7 Testing Web-Services
The last kind of JTR-runner is meant for testing web-services. These runners are called WS-enabled runners.
 
JTR 4.0 introduces a new web-services engine that leverages on the powerful JAX-WS 2.1.1 reference implementation. The former implementation based on Jakarta WSIF must now be considered obsolete and will soon be removed from JTR. This section will guide you through the steps required for writing WS-enabled runners, exploring one more example shipped with the jtrTestBenchClient sample JTR test-suite.
 
The WsArithmeticalTest runner
 
package jtr.test.jee.client;
 
import javax.xml.bind.JAXBElement;
import jtr.runners.AbstractWsRunner;
import jtr.test.IOutcome;
import jtr.test.jee.arithmetical.client.Sum;
import jtr.test.jee.arithmetical.client.SumResponse;
 
/**
 *
 * @author frusso
 * @version
 * @since
 */
public class WsArithmeticalTest extends AbstractWsRunner {
    
    /** Creates a new instance of WsArithmeticalTest */
    public WsArithmeticalTest() {
    }
 
    public void test() throws Throwable {
        userMsg = "Using WS-binding "+getBinding().getUniqueName();
        jtr.test.jee.arithmetical.client.ObjectFactory sof =
                new jtr.test.jee.arithmetical.client.ObjectFactory();
        Sum sumReq = sof.createSum();
        sumReq.setX(x);
        sumReq.setY(y);
        userMsg = userMsg + "\nSumming "+x+" and "+y;
        JAXBElement<Sum> req = sof.createSum(sumReq);
        JAXBElement<SumResponse> rsp = (JAXBElement) invoke(getBinding(),req);
        System.out.println("WS Sum is "+rsp.getValue().getReturn());
        userMsg = userMsg + "\nResult is "+rsp.getValue().getReturn();
    }
 
    public void receiveFailureNotification(Throwable t, String msg) {
    }
 
    public void cleanupResources() {
    }
 
    public void enrichOutcome(IOutcome outcome) {
        outcome.setUserObject(userMsg);
    }
    
    private String userMsg;
    private int x;
    private int y;
}
 
Extending the jtr.runners.AbstractWsRunner
Once again, one of the most important things to highlight is that in order to write a WS-enabled runner we have to inherit from the jtr.runners.AbstractWsRunner abstract class. As we can see we still have to provide our implementations of the all the methods discussed here.
 
The jtr.runners.AbstractWsRunner class provides the following facilities and information:
  1. method to perform synchronous request-response web-services invocations
  2. method to perform synchronous one-way web-services invocations
  3. methods to perform asynchronous web-services invocations
  4. accessor to the current WS-binding associated with the runner instance
  5.  
  6. Here are the most relevant methods meant for performing web-services invocations, exposed by the AbstractWsRunner and by the jtr.runners.IRunnerWs interface:
  7.  
  8.        /**
  9.      * Performs a synchronous invocation.
  10.      *
  11.      * @param binding The actual binding describing the web-services to invoke
  12.      * @param input The message
  13.      * @return The response
  14.      * @throws jtr.ws.WsProviderException
  15.      */
  16.     public Object invoke(Binding binding, Object input) throws WsProviderException;
  17.     
  18.     /**
  19.      * Performs a one-way webservice invocation.
  20.      *
  21.      * @param binding The actual binding describing the web-services to invoke
  22.      * @param input The message
  23.      * @throws jtr.ws.WsProviderException
  24.      */
  25.     public void invokeOneWay(Binding binding, Object input) throws WsProviderException;
  26.     
  27.     /**
  28.      * Performs an asynchronous invocation.
  29.      *
  30.      * @param binding The actual binding describing the web-service to invoke
  31.      * @param input The message
  32.      * @param rl The response listener to be notified when a response becomes available
  33.      * @return A reference to the <code>Future</code> instance representin the pending task
  34.      * @throws jtr.ws.WsProviderException
  35.      */
  36.     public Future<?> invokeAsync(Binding binding, Object input, IWsResponseListener rl)
  37.                      throws WsProviderException;
  38.     
  39.     /**
  40.      * Performs an asynchronous invocation.
  41.      *
  42.      * @param binding The actual binding describing the web-service to invoke
  43.      * @param input The message
  44.      * @return A reference to the response one should poll on
  45.      * @throws jtr.ws.WsProviderException
  46.      */
  47.     public IWsResponse invokeAsync(Binding binding, Object input) throws WsProviderException;
  48.  
  49. Web-Services invocations inputs & outputs
  50. Input and output messages for web-services invocations are instances of classes generated by means of the xjc JAXB binding compiler, starting from a WSDL file that describes the web-service(s) we want to invoke. For example, the following instruction:
  51.  
  52.  
  53. produces an output like this:
  54.  
  55. parsing a schema...
  56. compiling a schema...
  57. jtr/test/jee/ObjectFactory.java
  58. jtr/test/jee/Sum.java
  59. jtr/test/jee/SumResponse.java
  60. jtr/test/jee/package-info.java
  61.  
  62. This means that all the artifacts required to marshall and unmarshall both request and response messages have been successfully generated and we can use them. If you now go back to the runner code above, you can see that these classes are actually used to prepare the input message and to represent the received response.
  63.  
  64. This digression on web-services input and output object classes merely serves to highlight that you can still leverage on the full JAX-WS stack, that encloses JAXB as well, for representing input and output messages. If you need further information about either JAX-WS or JAXB, please refer to their official web-pages.
  65.  
  66. Preparing the jtr.xml file
  67. In order to have the above runner working, we need to define it into the out jtr.xml configuration file. Follows an example of how it should look like:
  68.  
  69. <?xml version = '1.0' encoding = 'UTF-8'?>
  70.  
  71. <!-- JTRunner is free software; you can redistribute it and/or modify
  72.     it under the terms of the GNU General Public License as published by
  73.     the Free Software Foundation; either version 2, or (at your option)
  74.     any later version.
  75. -->
  76.  
  77.       xsi:schemaLocation="http://jtrunner.sourceforge.net file:./config/jtr.xsd"
  78.       runs="10">
  79.  
  80.     <!-- JTR components factories -->
  81.     <factories>
        <factory key="IAssignmentPolicyFactory"
                 fqn="jtr.assigner.impl.DefaultAssignmentPolicyFactory" />
        <factory key="IOutcomeFactory" fqn="jtr.test.impl.DefaultOutcomeFactory" />
        <factory key="IWsHelperFactory" fqn="jtr.ws.jaxws.JaxWsHelperFactory" />
        <factory key="ITestCompletionListener"
                 fqn="jtr.test.impl.DefaultTestCompletionListener" />
        <factory key="ITestResultDisplayer" fqn="jtr.test.impl.DefaultTestResultDisplayer" />
        <factory key="ITestResultsExporter" fqn="jtr.test.results.exporters.impl.ExcelExporter" />
    </factories>
  1.  
  2.     <runner runs="2" binding="jboss-sum-soap-1.2">
  3.         <runner-fqn>jtr.test.jee.client.WsArithmeticalTest</runner-fqn>
  4.         <instance-count>2</instance-count>
  5.         <parameters-assignment-policy>
  6.             indexed
  7.         </parameters-assignment-policy>
  8.         <parameters>
  9.             <param name="sleepTime" value="14" />
  10.             <param name="x" value="1978" />
  11.             <param name="y" value="29" />
  12.         </parameters>
  13.         <parameters>
  14.             <param name="sleepTime" value="14" />
  15.             <param name="binding" value="glassfish-sum-soap-1.2" />
  16.             <param name="x" value="29" />
  17.             <param name="y" value="1978" />
  18.         </parameters>
  19.     </runner>
  20.  
  21.     <bindings>
  22.         <binding uniqueName="jboss-sum-soap-1.2"
  23.                  serviceNameSpace="http://jee.test.jtr/"
  24.                  serviceName="ArithmeticalService"
  25.                  portName="ArithmeticalPort"
  26.                  operationName="sum"
  27.                  serviceMode="PAYLOAD"
  28.                  jaxbObjectFactory="jtr.test.jee.arithmetical.client.ObjectFactory" />
  29.  
  30.         <binding uniqueName="glassfish-sum-soap-1.2"
  31.                  serviceNameSpace="http://jee.test.jtr/"
  32.                  serviceName="ArithmeticalService"
  33.                  portName="ArithmeticalPort"
  34.                  operationName="sum"
  35.                  serviceMode="PAYLOAD"
  36.                  jaxbObjectFactory="jtr.test.jee.arithmetical.client.ObjectFactory" />
  37.     </bindings>
  38. </test>
  39.  
  40. About the binding attribute
  41. Talking about the runner declaration, the only important thing to point-out is that we are using (both at the category-level and at instance-level in the second parameters-set) the binding attribute to declare that by default every WsArithmeticalTest instance must be fed with everything necessary for invoking the web-service uniquely identified by the jboss-sum-soap-1.2 name.
  42. Furthermore we say that all those instances that will be injected (fed) with the second parameters-set will be enabled to invoke the web-service uniquely identified by the glassfish-sum-soap-1.2 name.
  43.  
  44. About the bindings and binding elements
  45. In order to leverage on the JTR-runtime capabilities for invoking web-services, you must define in the jtr.xml file the web-services you want to invoke. This can be done by means of the bindings element and its binding sub-element.
  46.  
  47.  
  48. The bindings element acts as a container of one or many binding elements, each describing a particular web-service operation to invoke.
  49.  
  50. Each binding element requires the following attributes to properly describe a web-service operation to be invoked:
  51. uniqueName: the unique name that identifies this binding in the jtr.xml file and that will be used as an handle by those runners willing to invoke the described web-service
  52. serviceNameSpace: the targetNameSpace found in the WSDL
  53. serviceName: the service, present in the WSDL, that contains the operation to be invoked
  54. portName: the port exposed by the service, that contains the operation to be invoked
  55. operationName: the operation to be invoked
  56. wsdlLoc: where the WSDL can be found
  57. serviceMode: whether the endpoint accesses the message or the payload. Thus legal values are MESSAGE | PAYLOAD
  58. jaxbObjectFactory: the JAXB-generated class capable of producing input and output messages conforming with the grammar expressed in the WSDL
 
About using automatically generated clients
Typically there are many ways for invoking web-services. JTR leverages on DII (Dynamic Invocation Interface), but you could already have your somehow-generated clients or stubs and willing to use them
instead. Well, in such a case you can simply write a simple JSE runner (see here) that uses your clients or stubs to perform the actual web-service invocation.
Acting this way you get the best of both worlds: you continue using your clients/stubs but you can still take advantage of the JTR-runtime features such as parameterizations and stress-testing facilities, distributed testing and so on.