March 03, 2010

SOAP web service testing with soapUI

« Integration of soapUI tests in maven build lifecycle | Main | SoapUI limitations and workarounds : mock response test step »

SoapUI is a useful tool for testing web services. Not only makes it possible to test deployed web services, but it also offers the possibility to mock any "external" service needed by the service you want to test. As a result, you can test your web service independently from any other external service.

The following basic example describes how to test a service that computes the price of a trip (TripPriceService). It invokes one service that returns prices for hotel rooms (HotelPriceService) and one service that returns prices for flights (FlightPriceService).

Formula : price = duration * rooms * getRoomPrice() + adults * getFlightPrice(from, to)

Here are the WSDLs of the three services.

TripPriceService.wsdl

<?xml version='1.0' encoding='UTF-8'?><wsdl:definitions name="TripPriceServiceFacadeService" 
  targetNamespace="http://trip.price.service" xmlns:ns1="http://cxf.apache.org/bindings/xformat" 
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://trip.price.service" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:types>
    <xs:schema attributeFormDefault="unqualified" elementFormDefault="unqualified" 
      targetNamespace="http://trip.price.service" xmlns:tns="http://trip.price.service" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="getTripPrice" type="tns:getTripPrice" />
      <xs:element name="getTripPriceResponse" type="tns:getTripPriceResponse" />
      <xs:complexType name="getTripPrice">
       <xs:sequence>
         <xs:element minOccurs="0" name="trip" type="tns:trip" />
       </xs:sequence>
      </xs:complexType>
      <xs:complexType name="trip">
        <xs:sequence>
          <xs:element name="adults" type="xs:int" />
          <xs:element name="duration" type="xs:int" />
          <xs:element minOccurs="0" name="from" type="xs:string" />
          <xs:element name="rooms" type="xs:int" />
          <xs:element minOccurs="0" name="to" type="xs:string" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="getTripPriceResponse">
        <xs:sequence>
          <xs:element name="return" type="xs:float" />
        </xs:sequence>
      </xs:complexType>
      <xs:element name="TripPriceServiceException" type="tns:TripPriceServiceException" />
      <xs:complexType name="TripPriceServiceException">
        <xs:sequence />
      </xs:complexType>
    </xs:schema>
  </wsdl:types>
  <wsdl:message name="TripPriceServiceException">
    <wsdl:part element="tns:TripPriceServiceException" name="TripPriceServiceException">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="getTripPrice">
    <wsdl:part element="tns:getTripPrice" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="getTripPriceResponse">
    <wsdl:part element="tns:getTripPriceResponse" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="ITripPriceServiceFacade">
    <wsdl:operation name="getTripPrice">
      <wsdl:input message="tns:getTripPrice" name="getTripPrice">
    </wsdl:input>
      <wsdl:output message="tns:getTripPriceResponse" name="getTripPriceResponse">
    </wsdl:output>
      <wsdl:fault message="tns:TripPriceServiceException" name="TripPriceServiceException">
    </wsdl:fault>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="TripPriceServiceFacadeServiceSoapBinding" type="tns:ITripPriceServiceFacade">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="getTripPrice">
      <soap:operation soapAction="" style="document" />
      <wsdl:input name="getTripPrice">
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output name="getTripPriceResponse">
        <soap:body use="literal" />
      </wsdl:output>
      <wsdl:fault name="TripPriceServiceException">
        <soap:fault name="TripPriceServiceException" use="literal" />
      </wsdl:fault>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="TripPriceServiceFacadeService">
    <wsdl:port binding="tns:TripPriceServiceFacadeServiceSoapBinding" name="TripPriceServiceFacadePort">
      <soap:address location="http://localhost:8080/trip-price-0.0.1-SNAPSHOT/webservices/TripPriceService" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

HotelPriceService.wsdl

<?xml version='1.0' encoding='UTF-8'?><wsdl:definitions name="HotelPriceServiceFacadeService" 
  targetNamespace="http://external.services/hotel" xmlns:ns1="http://cxf.apache.org/bindings/xformat" 
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://external.services/hotel" 
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:types>
    <xs:schema elementFormDefault="unqualified" targetNamespace="http://external.services/hotel" 
      version="1.0" xmlns:tns="http://external.services/hotel" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="getRoomPrice" type="tns:getRoomPrice" />
      <xs:element name="getRoomPriceResponse" type="tns:getRoomPriceResponse" />
      <xs:complexType name="getRoomPrice">
        <xs:sequence />
      </xs:complexType>
      <xs:complexType name="getRoomPriceResponse">
        <xs:sequence>
          <xs:element name="return" type="xs:float" />
        </xs:sequence>
      </xs:complexType>
    </xs:schema>
  </wsdl:types>
  <wsdl:message name="getRoomPrice">
    <wsdl:part element="tns:getRoomPrice" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="getRoomPriceResponse">
    <wsdl:part element="tns:getRoomPriceResponse" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="IHotelPriceServiceFacade">
    <wsdl:operation name="getRoomPrice">
      <wsdl:input message="tns:getRoomPrice" name="getRoomPrice">
    </wsdl:input>
      <wsdl:output message="tns:getRoomPriceResponse" name="getRoomPriceResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="HotelPriceServiceFacadeServiceSoapBinding" type="tns:IHotelPriceServiceFacade">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="getRoomPrice">
      <soap:operation soapAction="" style="document" />
      <wsdl:input name="getRoomPrice">
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output name="getRoomPriceResponse">
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="HotelPriceServiceFacadeService">
    <wsdl:port binding="tns:HotelPriceServiceFacadeServiceSoapBinding" name="HotelPriceServiceFacadePort">
      <soap:address location="http://localhost:8088/external-services-0.0.1-SNAPSHOT/webservices/HotelPriceService" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

FlightPriceService.wsdl

<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions name="FlightPriceServiceFacadeService" targetNamespace="http://external.services/flight" 
  xmlns:ns1="http://cxf.apache.org/bindings/xformat" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
  xmlns:tns="http://external.services/flight" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:types>
    <xs:schema attributeFormDefault="unqualified" elementFormDefault="unqualified" 
      targetNamespace="http://external.services/flight" xmlns:tns="http://external.services/flight" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="getFlightPrice" type="tns:getFlightPrice" />
      <xs:element name="getFlightPriceResponse" type="tns:getFlightPriceResponse" />
      <xs:complexType name="getFlightPrice">
        <xs:sequence>
          <xs:element minOccurs="0" name="from" type="xs:string" />
          <xs:element minOccurs="0" name="to" type="xs:string" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="getFlightPriceResponse">
        <xs:sequence>
          <xs:element name="return" type="xs:float" />
        </xs:sequence>
      </xs:complexType>
      <xs:element name="LocationNotFoundException" type="tns:LocationNotFoundException" />
      <xs:complexType name="LocationNotFoundException">
        <xs:sequence />
      </xs:complexType>
    </xs:schema>
  </wsdl:types>
  <wsdl:message name="LocationNotFoundException">
    <wsdl:part element="tns:LocationNotFoundException" name="LocationNotFoundException">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="getFlightPrice">
    <wsdl:part element="tns:getFlightPrice" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="getFlightPriceResponse">
    <wsdl:part element="tns:getFlightPriceResponse" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="IFlightPriceServiceFacade">
    <wsdl:operation name="getFlightPrice">
      <wsdl:input message="tns:getFlightPrice" name="getFlightPrice">
    </wsdl:input>
      <wsdl:output message="tns:getFlightPriceResponse" name="getFlightPriceResponse">
    </wsdl:output>
      <wsdl:fault message="tns:LocationNotFoundException" name="LocationNotFoundException">
    </wsdl:fault>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="FlightPriceServiceFacadeServiceSoapBinding" type="tns:IFlightPriceServiceFacade">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="getFlightPrice">
      <soap:operation soapAction="" style="document" />
      <wsdl:input name="getFlightPrice">
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output name="getFlightPriceResponse">
        <soap:body use="literal" />
      </wsdl:output>
      <wsdl:fault name="LocationNotFoundException">
        <soap:fault name="LocationNotFoundException" use="literal" />
      </wsdl:fault>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="FlightPriceServiceFacadeService">
    <wsdl:port binding="tns:FlightPriceServiceFacadeServiceSoapBinding" name="FlightPriceServiceFacadePort">
      <soap:address location="http://localhost:8088/external-services-0.0.1-SNAPSHOT/webservices/FlightPriceService" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

For the next steps we assume the web service we want to test is deployed and the external services are not.


1. How to create a soapUI project

  • In the menu select "File" -> "New soapUI Project"
  • Set the project name, for example "trip-price-service"
  • Set the initial WSDL, for example "http://localhost:8080/trip-price-0.0.1-SNAPSHOT/webservices/TripPriceService?wsdl"
  • Click "OK"

As a result, you get the "trip-price-service" project containing the "TripPriceServiceFacadeServiceSoapBinding" interface.


2. How to generate a test suite

  • Right click on the "TripPriceServiceFacadeServiceSoapBinding" interface and select "Generate TestSuite"
  • Click "OK"
  • Enter a name for your test suite, for example "TripPriceServiceFacadeServiceSoapBinding TestSuite"
  • Click "OK"

As a result you get the "TripPriceServiceFacadeServiceSoapBinding TestSuite" test suite, that includes the "getTripPrice TestCase" test case. The test case already contains the generated "getTripPrice" test request.


3. How to configure the test case

Setting a timeout for the test case is a good habit, so your test does not run forever, in case something goes wrong.

  • Double click the test case
  • Click the "Set options for the test case" button (with a monkey wrench and a screwdriver)
  • Set a timeout in milliseconds, for example "5000"
  • Click "OK"

4. How to configure the test request

  • Double-click the "getTripPrice" test request
  • Edit the request to ask for the price of the following trip : from Berlin to Paris, for 2 adults, lasting 3 days, one room needed
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:trip="http://trip.price.service">
<soapenv:Header/>
  <soapenv:Body>
    <trip:getTripPrice>
      <trip>
        <adults>2</adults>
        <duration>3</duration>
        <from>Berlin</from>
        <rooms>1</rooms>
        <to>Paris</to>
      </trip>
    </trip:getTripPrice>
  </soapenv:Body>
</soapenv:Envelope>
  • Click the "Submit request to specified endpoint URL" button (green triangle)

As a result, we get a SOAP fault, because the external services we need are not available. We will mock all of them.

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <soap:Fault>
      <faultcode>soap:Server</faultcode>
      <faultstring>Could not send Message.</faultstring>
    </soap:Fault>
  </soap:Body>
</soap:Envelope>

5. How to mock external services

5.1 How to import the WSDL of the external service

  • Right click on the projet and select "Add WSDL"
  • Set the WSDL location, for example "/home/ubuntu/workspace/test-webservice-soapui/trip-price/trip-price-service/src/main/resources/wsdl/HotelPriceService.wsdl"
  • Click "OK"

As a result, it adds a new interface to the project : "HotelPriceServiceFacadeServiceSoapBinding".

5.2 How to add a mock response to the test case

  • Double click the test case to open the test case editor.
  • Right click and select "Append Step" -> "Mock Response"
  • Specify a name for the new step, for example "getRoomPrice Mock Response" and click "OK"
  • Select the "getRoomPrice" operation of the "HotelPriceServiceFacadeServiceSoapBinding" interface.
  • Set the port, here "8088"
  • Set the path, here "/external-services-0.0.1-SNAPSHOT/webservices/HotelPriceService"
  • Click "OK"
  • Edit the generated response, to return a price, for example "55.0"
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:hot="http://external.services/hotel">
  <soapenv:Header/>
  <soapenv:Body>
    <hot:getRoomPriceResponse>
      <return>55.0</return>
    </hot:getRoomPriceResponse>
  </soapenv:Body>
</soapenv:Envelope>
  • Set the start step of the mock response in the "MockResponse Properties" tab to "getTripPrice". So the mock service will start listening to requests as soon as the getTripPrice request is send.

5.3 How to add assertions on the getRoomPrice request

Here we can check the request schema and the parameter values

We launch the test case, to trigger a request to the mock service, it will make assertion configuration easier.

  • Click the "Runs this testcase" button (green triangle) in the test case editor

You should see a request in the mock response editor.

  • Click the "Assertions" tab
  • Click the "Adds an assertion to this item" button
  • Select "Schema Compliance" and click "OK"
  • Check the definition url to validate by and click "OK"

The assertion should appear as valid.

5.4 Now we do the same for FlightPriceService.

  • Right click on the projet and select "Add WSDL"
  • Set the WSDL location, for example "/home/ubuntu/workspace/test-webservice-soapui/trip-price/trip-price-service/src/main/resources/wsdl/FlightPriceService.wsdl"
  • Click "OK"

As a result, it adds a new interface to the project : "FlightPriceServiceFacadeServiceSoapBinding".

  • Double click the test case to open the test case editor.
  • Right click and select "Append Step" -> "Mock Response"
  • Specify a name for the new step, for example "getFlightPrice Mock Response" and click "OK"
  • Select the "getFlightPrice" operation of the "FlightPriceServiceFacadeServiceSoapBinding" interface.
  • Set the port, here "8088"
  • Set the path, here "/external-services-0.0.1-SNAPSHOT/webservices/FlightPriceService"
  • Click "OK"
  • Edit the generated response, to return a price, for example "49.99"

  • Set the start step of the mock response in the "MockResponse Properties" tab to "getTripPrice". So the mock service will start listening to requests as soon as the getTripPrice request is send.
  • Click the "Runs this testcase" button (green triangle) in the test case editor

You should see a request in the mock response editor.

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <ns2:getFlightPrice xmlns:ns2="http://external.services/flight">
      <from>Berlin</from>
      <to>Paris</to>
    </ns2:getFlightPrice>
  </soap:Body>
</soap:Envelope>
  • Click the "Assertions" tab
  • Click the "Adds an assertion to this item" button
  • Select "Schema Compliance" and click "OK"
  • Check the definition url to validate by and click "OK"

The assertion should appear as valid.

  • Click the "Adds an assertion to this item" button
  • Select "XPath Match" and click "OK", this opens the XPath Match configuration window
  • Click "Declare" to generate declarations automatically
declare namespace soap='http://schemas.xmlsoap.org/soap/envelope/';
declare namespace ns2='http://external.services/flight';
  • Query the "from" field //ns2:getFlightPrice/from
  • Set the expected result, in this example "Berlin"
  • Click "Save"

The assertion should appear as valid.

Do the same for the "to" field and check it is Paris.


6 How to check the response

Run the test case, it should now be successful.

  • Open the test request editor
  • Click the "Assertions" tab
  • Add a "Schema Compliance" assertion, to check the response schema
  • Add a "Not SOAP Fault" assertion, to check the response is not a SOAP fault
  • Add a "SOAP Response" assertion, to check the response is a SOAP response
  • Add a "XPath Match" assertion to check the price

XPath Expression

declare namespace soap='http://schemas.xmlsoap.org/soap/envelope/';
declare namespace ns2='http://trip.price.service';
//ns2:getTripPriceResponse/return

Expected Result : 264.98

(3 * 1 * 55 + 2 * 49.99)

Now your test case is complete.


Related topics:

"Web service testing with soapUI: exceptions"
"Integration of soapUI tests in maven build lifecycle"

Technorati Tags:

Posted by nadege.griesser at 4:51 PM in Testing

 

[Trackback URL for this entry]

Comment: Dave Lowerre at Mo, 5 Apr 9:16 PM

This was VERY helpful. Testing SOAP interfaces is a bit tricky, and this helped me validate a third party SOAP web service in less than half an hour from downloading soapUI, installing it, and testing. Nice.

Comment: Boss at Fr, 28 Mai 10:42 PM

Nice article. I'm just working on a textual and graphical DSL for a framework, which allows generation of WS (interface + functionality) on remote hosts without having to take care of deployment. If you're interested, I'll send you a link when I'm done. Greetings.

Comment: kiran at Mo, 21 Jun 7:50 AM

Very Usefull Article. I need to test an Asynchronous SOAP webservice and Iam using SOAPUI Pro for that. I had developed a Test case consisting of two steps
1.create PO Request -Which submits a SOAP request to an asynchronous webservice
2.Mock Response - This is a Mock Response step .
when I ran the Test Case -the Mock Response step waits forever and never completes. Can you please help me with the Set up I need to do like path, Port , host or other details I should give .
Thanks in advance ,
Kiran

Comment: love at Mo, 1 Nov 6:50 PM

cool

Comment: :] at Mo, 1 Nov 6:50 PM

cool

Comment: :] at Mo, 1 Nov 6:50 PM

cool

Comment: Richard at Di, 9 Nov 4:09 PM

I am tried to follow the step to practice, but in the step:
Set the start step of the mock response in the "MockResponse Properties" tab to "getTripPrice". So the mock service will start listening to requests as soon as the getTripPrice request is send.

Where is the "MockResponse Properties" tab?

Comment: Richard at Di, 9 Nov 4:19 PM

I am new to SOAPUI, and trying to follow the steps to practice, regarding to the step:

Set the start step of the mock response in the "MockResponse Properties" tab to "getTripPrice". So the mock service will start listening to requests as soon as the getTripPrice request is send.

Where is the "MockResponse Properties" tab

Comment: Richard at Di, 9 Nov 4:27 PM

I am trying to follow the steps to practice, in the following step:

Set the start step of the mock response in the "MockResponse Properties" tab to "getTripPrice". So the mock service will start listening to requests as soon as the getTripPrice request is send.

Where is the MockResponse Properties tab?

Comment: M.Sreenivaa Rao at Do, 2 Dez 12:23 PM

Topic is very elaborative and good one.

Comment: radhika at Do, 9 Dez 4:55 PM

Good Stuff

Comment: Vikas at Fr, 6 Mai 7:50 PM

I am a service provider.. any idea how do I make sure my service is working fine with clients generating stubs using different framework.

Pingback: SOAP web service testing with soapUI - Websphere Tutorial at Mo, 6 Jun 2:23 PM

SOAP web service testing with soapUI
is a good tutorial show you about SOAP web service testing with

Pingback: SoapUI tests in maven Integration - Websphere Tutorial at Di, 7 Jun 2:03 PM

SOAP web service testing with soapUI
is a good tutorial show you how to use SoapUI tests in maven Integration: This article extends the basic example described in &#8220;Web service testing with soapUI&#8221;. It describes how to integrate soapUI tests in maven build lifecycle, using

Comment: Manoj at Fr, 19 Aug 5:18 AM

while i am adding a wsdl to the project its creating one xml request template but that request template is missing the parameters or attributes we shld send in the request....can any one please tell me what might be the problem??

Comment: Alka at Di, 17 Jan 9:45 AM

Hi,

Packt Publishing is looking for Technical reviewers on "Web Services Testing with soapUI" If interested in reviewing it, contact alkan@packtpub.com

Comment: Armands at Do, 1 Mrz 1:47 PM

Does anyone know how to test the HL7 Web Service in SoapUI ?
Is there any example and description of this case?

Regards.

Armands

Comment: Armands at Do, 1 Mrz 1:50 PM

Does anyone know how to test the HL7 Web Service in SoapUI ?
Is there any example and description of this case?

Regards.

Armands
Armands.Bruns@lattelecom.lv

Comment: shashikant at Di, 20 Mrz 3:58 AM

From where i will get detailed info. about how to publish web service into eclipse.
i have generated .aar files with axis2 but don't know what to do further....

Comment: nadege.griesser at Fr, 23 Mrz 5:53 AM

while running of service method i am getting error 1.faultstring "Unmarshalling Error:"
2.faultstring "Fault occurred while processing"
3.org.hibernate.hql.ast.QuerySyntaxException: unexpected AST node: - near line 1, column 55 [FROM com.phoenix.billing.vo.GeneralChrgTVO o WHERE 100-2].
4.JTA transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: ARJUNA-16053 Could not commit transaction.
Please kindly help me out regarding this type of error and give me example hw to test this type of service method.
in advance ThankQ.

Your comment:

(not displayed)
 
 
 

Live Comment Preview:

 
 
test