官术网_书友最值得收藏!

Developing a SOAP web service test-first

SoapUI is often used to retrofit tests around web services that are already at least partially developed. To follow a test-first or test-driven development (TDD) approach requires that we first set up failing tests and then provide a service implementation in order to pass them. In this recipe, we'll see how SoapUI can be used to facilitate test-first development for the invoice web service generated in the previous recipe.

Getting ready

We'll need the WSDL from the previous recipe to set up our SoapUI project (<chapter1 samples>/soap/invoicev1/wsdl/invoice_v1.wsdl).

The Java code for the completed web service implementation can be found at <chapter1 samples>/soap/invoicev1_impl.

The project can be found at <chapter1 samples>/invoice-soap-v1-soapui-project.xml.

Tip

Eclipse setup

Optionally, it is very easy to set up an Eclipse project to make light work of the test, edit, compile, and run cycle. First, import the sample code and then run the service as a standard Java application.

How to do it...

Firstly, we'll set up a couple of simple failing tests to assert what we expect back from the getInvoice operation and then provide basic implementation to pass them. Next, we'll update the invoice WSDL definition to provide an additional createInvoice operation, write new failing tests, and finally provide basic code to pass those. Perform the following steps:

  1. To create the SoapUI project and generate the initial PortBinding, Test Suite, TestCase, and Test Request TestStep, right-click on your Workspace and select New SOAP Project. In the window, enter/select the following and click on OK:
    • Project Name: InvoiceService
    • Initial WSDL: chapter1 samples>/soap/invoicev1/wsdl/invoice_v1.wsdl
    • Leave Create Requests ticked and also tick Create TestSuite
  2. In the Generate TestSuite window, select the following options and click on OK:
    • Leave Style as One TestCase for Each Operation
    • Change Request Content to Use existing Requests in Interface
  3. Accept the suggested TestSuite name as InvoicePortBinding TestSuite in the pop up and click on OK. All expected SoapUI test artifacts should now be generated in your project.
  4. Now, we can write a simple failing test to assert what we expect a successful getInvoice request to return. Under the first TestStep option, double-click on getInvoice and you should see the SOAP request:
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:inv="http://soapui.cookbook.samples/schema/invoice">
       <soapenv:Header/>
       <soapenv:Body>
          <inv:getInvoice>
             <inv:invoiceNo>?</inv:invoiceNo>
          </inv:getInvoice>
       </soapenv:Body>
    </soapenv:Envelope>
  5. Change the invoiceNo (?) value to something more memorable, for example, 12345.
  6. Now, start the stub invoice service generated in the previous recipe and submit the request by clicking on the green arrow. You should see a stubbed response, like the one shown in the following code:
    <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
       <S:Body>
          <InvoiceDocument xmlns="http://soapui.cookbook.samples/schema/invoice">
             <invoiceNo>12345</invoiceNo>
             <company/>
             <amount>0.0</amount>
          </InvoiceDocument>
       </S:Body>
    </S:Envelope>
  7. Next, let's create some SoapUI Assertions to specify the invoice property values we expect to see:
    • invoiceNo = 12345
    • company = Test Company
    • amount = 100.0

Since we're dealing with SOAP XML, let's add 3 XPath Assertions to check these values in the response. SoapUI Pro users will find this easy, thanks to the convenient XPath builder. Open source users can either be 'hardcore' and write them from scratch or just copy the details provided.

Tip

XPath Help

Even the Pro version's XPath builder is of less use when you cannot directly retrieve a response XML to build from, that is, when there is no service at all! As a workaround, you can get SoapUI to generate a sample response XML by going to Add Step | SOAP Mock Response TestStep from the TestCase, and then copy the response XML into a helpful XPath tool to write the XPath expression, for example, http://www.freeformatter.com/xpath-tester.html. Paid-for tools such as XML Spy will also help a lot in these areas. You may also find http://www.w3schools.com/XPath/xpath_syntax.asp helpful.

So let's add 3 XPath Assertions. Edit the REST Request TestStep, under the Assertions tab and right-click on Add Assertion and add a new XPath Assertion to check the response's invoiceNo=12345, company=Test Company, and amount=100.0:

Have a look at the following screenshot for better clarity:

How to do it...

Running the TestCase should now fail 2 of the assertions. Note that InvoiceNoShouldBe12345 will work, thanks to Apache CXF passing through the request's invoiceNo to the response (see InvoicePortImpl.java)! It is still worth asserting the invoiceNo value, as it is a requirement.

Tip

Server timed out?

If you instead see a connection refused error, then check whether your server hasn't exited after 5 minutes. It's easy to change this timeout (see the previous recipe).

Now, we can add a very basic service implementation to pass this test. We just need to implement the getInvoice(…) method in InvoicePortImpl.java. The simplest implementation option is to just edit InvoicePortTypeImpl.java and hardcode the expected values:

try {
    java.lang.String companyValue = "Test Company";
    company.value = companyValue;
    java.lang.Double amountValue = 100.0d;
    amount.value = amountValue;
} catch (java.lang.Exception ex) {
    ex.printStackTrace();
    throw new RuntimeException(ex);
}

Tip

TDD

Strictly speaking, we should first write a unit test before implementing the method, for example, using JUnit.

Next, recompile this and restart the server:

cd <chapter1 samples>/soap/invoicev1
javac src/main/java/ws/invoice/v1/*.java -d target/classes/

And start it again:

cd <chapter1 samples>/soap/invoicev1/target/classes
java ws.invoice.v1.InvoicePortType_InvoicePort_Server

Rerun TestCase, which should now pass!

How it works...

This recipe builds on all the same JAX-WS web service code explained in the previous recipe. This time, we add a very simple stub implementation to return the minimum necessary to pass the test. For those who haven't seen JAX-WS before, the use of the javax.xml.ws.Holder wrapper object means that we don't have to explicitly set the invoiceNo, as it is passed through the request (for more information, see http://tomee.apache.org/examples-trunk/webservice-holder/README.html).

There's more...

As mentioned in the previous recipe, SoapUI mocks (see Chapter 3, Developing and Deploying Dynamic REST and SOAP Mocks) can often provide a convenient and often quicker alternative if all you need is a disposable test version of your web service with basic functionality. Also, if you want your web service stub to be the basis for ongoing development, then you may want to consider using a build framework like Gradle or Maven to manage the build, deploy, and test cycle. Chapter 5, Automation and Scripting, looks at different ways to use build frameworks and scripts to run SoapUI tests (and mocks) after your web service is built and deployed. If your stub implementations become more complicated, you may also want unit tests.

The SOAP web service stub journey continues in the next recipe where we use SoapUI to help us update the project, tests, and services to add a createInvoice operation.

See also

主站蜘蛛池模板: 射阳县| 卢龙县| 许昌市| 临江市| 环江| 丽江市| 桐城市| 池州市| 古浪县| 梨树县| 聂拉木县| 敖汉旗| 当阳市| 元朗区| 夏津县| 天柱县| 格尔木市| 宜昌市| 扎囊县| 吐鲁番市| 湘潭县| 五指山市| 清水县| 梁河县| 东城区| 杨浦区| 永定县| 东至县| 建阳市| 昌图县| 运城市| 平昌县| 赤水市| 全州县| 天门市| 上虞市| 固安县| 张掖市| 泰兴市| 扶余县| 涪陵区|