Guide: Messaging in test cases

Track Test bed setup

This guide walks you through the process of including messaging in GITD TDL test cases.

What you will achieve

At the end of this guide you will have created a GITB TDL test suite that includes two test cases that handle:

  • Receiving content sent via HTTP.
  • Sending content over HTTP.
  • Validating the exchanged content as well as additional communication properties.

The resulting test suite will be self-contained, requiring only the minimal configuration on the side of the test bed to be used.

What you will need

How to complete this guide

This guide builds upon the testing scenario and resulting test suite from Guide: Creating a test suite. If you have not already completed this, you should check its section Step 1: Define your testing needs to understand at least the testing scenario being considered. In terms of the test cases you will create in the current guide these serve as extensions to the previously created test suite. You may:

  • Follow the Steps of the previous guide to create the initial version of the test suite step by step, or,
  • Skip them by downloading the test suite to use from here.

If you choose to skip the previous steps make sure you extract the test suite archive into a folder named testSuite1. The contents of this folder following the extraction should be as follows:

testSuite1
 |
 +-- artifacts
 |    |
 |    +-- PurchaseOrder.xsd
 |
 +-- testCase1.xml
 +-- testSuite.xml

Steps

Carry out the following steps to complete this guide.

Step 1: Define your testing needs

In Guide: Creating a test suite we assumed that you are part of a project to define a new specification for the exchange of purchase orders between EU retailers. Up to this point your project’s testing needs have focused only on the content itself without addressing how purchase orders are actually exchanged.

Your project’s experts have now also introduced a web service interface to make this exchange consistent. Retailer systems will need to implement this to receive orders but also be able to call it to send orders to other retailers. In terms of requirements:

  • The interface is a REST service listening for HTTP POST requests to a request path /receiveOrder.
  • The body of these requests is the purchase order XML.
  • The response to such requests must contain only a text reference identifier of the form REF-[\d]+, i.e. REF- followed by one or more digits.

As an example, a valid request would be as follows:

POST /receiveOrder HTTP/1.1
...
Content-Type: text/xml

<?xml version="1.0"?>
<purchaseOrder xmlns="http://itb.ec.europa.eu/sample/po.xsd" orderDate="2018-01-22">
    ...
</purchaseOrder>

A valid response to such a request would be:

HTTP/1.1 200 OK
...
Content-Type: text/plain

REF-0123456789

Based on this addition to the specification, your project’s testing needs have also evolved. The conformance testing services offered up to now included a service for developers to upload purchase orders for validation. These will now be extended with the addition of a simulator for the defined service specification. This simulator will be able to:

  • Receive purchases orders from retailer systems and validate the request properties and content.
  • Send sample purchase orders to retailer systems and validate their response.

Step 2: Design your test suite

Up to this point you had defined a single Retailer actor for use in your test suite. A second actor named Simulated retailer will be added to support the new communication needs. Although not defined in the specification, this actor is needed since our test cases need two distinct actors to carry out messaging. The Simulated retailer will never of course be defined as the SUT (System Under Test).

In terms of test suite structure, we will update the existing test suite rather than create a new one. You will do so by complementing the existing test case with two additional ones, one to receive a purchase order and the other to send it. Note that you could define only a single test case both for sending and receiving but doing so would suggest that it is a messaging sequence defined as an expected process in the specification. Since there is no such process defined, the cleaner approach is to create distinct test cases as this allows conformance testing to focus separately on sending and receiving.

To better understand this choice consider a retailer system that has successfully implemented the service interface (i.e. it can receive purchase orders) but has not yet been able to send them to other retailers. If you define a single test case that e.g. first expects the system to receive a purchase order and then to send one, this would fail even though the receiving part is successful. Moreover, if the steps are reversed in the test case, the system would be unable to test its working receive implementation as it would be blocked by its failure to send.

Finally, regarding the purchase orders sent by the simulator to retailer systems, we will assume for simplicity that you will use a fixed one that will be bundled in the test suite.

Step 3: Update the test suite file

Edit file testCase1/testSuite.xml by adding the highlighted lines:

<?xml version="1.0" encoding="UTF-8"?>
<testsuite id="testSuite1" xmlns="http://www.gitb.com/tdl/v1/" xmlns:gitb="http://www.gitb.com/core/v1/">
    <metadata>
        <gitb:name>testSuite1</gitb:name>
        <gitb:description>Test suite to validate the EU purchase order specification.</gitb:description>
        <gitb:version>1.0</gitb:version>
    </metadata>
    <actors>
        <gitb:actor id="Retailer">
            <gitb:name>Retailer</gitb:name>
            <gitb:desc>The EU retailer system that needs to be capable of producing and processing purchase orders.</gitb:desc>
            <gitb:endpoint name="address" desc="The address to contact the retailer system">
                <gitb:config name="network.host" desc="The host where the system is listening" kind="SIMPLE" use="R"/>
                <gitb:config name="network.port" desc="The port where the system is listening" kind="SIMPLE" use="R"/>
                <gitb:config name="http.uri" desc="The HTTP request URI to reach the system" kind="SIMPLE" use="O"/>
            </gitb:endpoint>
        </gitb:actor>
        <gitb:actor id="SimulatedRetailer">
            <gitb:name>Simulated retailer</gitb:name>
            <gitb:desc>A simulated EU retailer system used for testing purposes.</gitb:desc>
        </gitb:actor>
    </actors>
    <testcase id="testCase1_upload"/>
    <testcase id="testCase2_send"/>
    <testcase id="testCase3_receive"/>
</testsuite>

The updates introduced to the test suite definition are as follows:

  • The Retailer actor has been updated to include the address configuration endpoint. This is used to identify the Retailer’s service endpoint in terms of host name (network.host), port (network.port) and base request path (http.uri). This information is used as follows:

    • When sending messages to the test bed, to ensure only traffic from network.host are accepted for the test session.
    • When receiving messages from the test bed to define the recipient address the test bed needs to use.
  • Two new test cases testCase2_send and testCase3_receive are defined as part of the test suite that you will create next.

Step 4: Create the test case for sending

The next step is to create the test case that will require the retailer’s system (i.e. the SUT) to send a purchase order to the test bed (i.e. the simulated retailer).

Within the test suite folder create file testCase2.xml with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<testcase id="testCase2_send" xmlns="http://www.gitb.com/tdl/v1/" xmlns:gitb="http://www.gitb.com/core/v1/">
    <metadata>
        <gitb:name>testCase2_send</gitb:name>
        <gitb:version>1.0</gitb:version>
        <gitb:description>Test case to test that an EU retailer system can correctly send a purchase order.</gitb:description>
    </metadata>
    <imports>
        <artifact type="schema" encoding="UTF-8" name="purchaseOrderXSD">testSuite1/artifacts/PurchaseOrder.xsd</artifact>
    </imports>
    <variables>
        <var name="referenceIdentifier" type="string">
            <value>REF-0123456789</value>
        </var>
    </variables>
    <actors>
        <gitb:actor id="Retailer" name="Retailer" role="SUT"/>
        <gitb:actor id="SimulatedRetailer" name="Simulated retailer" role="SIMULATED"/>
    </actors>
    <steps>
        <btxn from="Retailer" to="SimulatedRetailer" txnId="t1" handler="HttpMessaging"/>
        <receive id="dataReceived" desc="Receive request" from="Retailer" to="SimulatedRetailer" txnId="t1"/>
        <send desc="Send acknowledgement" from="SimulatedRetailer" to="Retailer" txnId="t1">
            <config name="http.method">POST</config>
            <config name="status.code">200</config>
            <input name="http_body">$referenceIdentifier</input>
        </send>
        <etxn txnId="t1"/>
        <verify handler="StringValidator" desc="Check request path">
            <input name="actualstring">$dataReceived{http_path}</input>
            <input name="expectedstring">'/receiveOrder'</input>
        </verify>
        <verify handler="XSDValidator" desc="Validate purchase order">
            <input name="xmldocument">$dataReceived{http_body}</input>
            <input name="xsddocument">$purchaseOrderXSD</input>
        </verify>
    </steps>
</testcase>

This test case specifies the following:

  • Its metadata, similar to what you defined as part of the first test case. Note testCase2_send set as the id and name that match it with the test suite.
  • The XSD to use for the validation is imported as purchaseOrderXSD.
  • A fixed referenceIdentifier string variable is added to define the response content the test bed will use.
  • The steps section defines the required messaging and validation logic.

A first important point to highlight is the use of a messaging transaction with btxn as a wrapper for the communication to take place. The handler implementation for this is HttpMessaging, an embedded messaging handler that can be used to send and receive HTTP messages. The transaction encapsulates the receive step where the test bed will expect a message to arrive, followed by the send step to send back a response, and completes with the etxn step. Notice that on each step the use of the from and to attributes that identify the direction of the communication using the defined actor identifiers. Some additional important points to note are:

  • In the receive step an id of dataReceived is used. This is the name under which received data will be stored in the test session context.
  • The send step defines the basics of the response (method POST and status 200) and also uses the $referenceIdentifier expression to define its content.

Following the messaging transaction the test case moves ahead with the validation steps. The first thing to do is check that the received request path was what we expect, i.e. /receiveOrder. This is checked using a string comparison with the embedded StringValidator. Following this, the payload of the received request is checked against the purchase order XSD using an XSDValidator. What is interesting to highlight is the use of the dataReceived context variable that stores the received message:

  • $dataReceived{http_path} for the path of request.
  • $dataReceived{http_body} for the request’s body payload.

Step 5: Create the test case for receiving

What remains is to complete the test case that will allow a retailer’s system to receive a purchase order sent by the test bed (i.e. the simulated retailer).

Within the test suite folder create file testCase3.xml with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<testcase id="testCase3_receive" xmlns="http://www.gitb.com/tdl/v1/" xmlns:gitb="http://www.gitb.com/core/v1/">
    <metadata>
        <gitb:name>testCase3_receive</gitb:name>
        <gitb:version>1.0</gitb:version>
        <gitb:description>Test case to test that an EU retailer system can correctly receive a purchase order.</gitb:description>
    </metadata>
    <imports>
        <artifact type="binary" encoding="UTF-8" name="purchaseOrder">testSuite1/artifacts/sample.xml</artifact>
    </imports>
    <actors>
        <gitb:actor id="Retailer" name="Retailer" role="SUT"/>
        <gitb:actor id="SimulatedRetailer" name="Simulated retailer" role="SIMULATED"/>
    </actors>
    <steps>
        <btxn from="SimulatedRetailer" to="Retailer" txnId="t1" handler="HttpMessaging"/>
        <send desc="Send request" from="SimulatedRetailer" to="Retailer" txnId="t1">
            <config name="http.method">POST</config>
            <config name="http.uri.extension">/receiveOrder</config>
            <input name="http_body">$purchaseOrder</input>
        </send>
        <receive id="dataReceived" desc="Get response" from="Retailer" to="SimulatedRetailer" txnId="t1"/>
        <etxn txnId="t1"/>
        <verify handler="RegExpValidator" desc="Validate reference identifier">
            <input name="input">$dataReceived{http_body}</input>
            <input name="expression">"^REF\-\d+$"</input>
        </verify>
    </steps>
</testcase>

In terms of test case structure a notable change is that we no longer import the PurchaseOrder.xsd file as we don’t plan on validating received purchase orders. Validation in this case takes place on the identifier that is returned from the retailer’s system. What is imported (as variable purchaseOrder) is the sample purchase order that the test bed will be sending.

The sample you will use is available here. Download this, and place it in folder testSuite1/artifacts ensuring that its name is sample.xml.

Note

Changing file contents at runtime: The sample.xml file you included in the test suite contains fixed content and will be used as-is. A more flexible approach could be to use this as a template file with variable parts that will be replaced during test execution using values from the session context. More information on how this works is available in the Expressions and template files section of the GITB TDL documentation.

Lets take a closer look now at the steps involved in this test case. As with all messaging cases, the first step is to create a transaction with the btxn step. This contains a send for the test bed to send the purchaseOrder to the retailer system, followed by a receive which, given it is wrapped in a transaction started with a send, is used to capture the synchronous response. Notice here again the to and from attributes of the btxn, send and receive steps that are set to match the communication direction for this test case. With regards to the send what is interesting to highlight are:

  • The definition of the POST and /receiveOrder path extension as defined in your project’s specification (passed respectively as the http.method and http.uri.extension configuration properties).
  • The use of the imported purchaseOrder (passed as the http_body input).

Concerning the receive step what is important to note is the dataReceived value set as the id which corresponds to the key under which the returned data will be stored for subsequent use.

Once the messaging is complete the next step is to validate the response. For this purpose we use the RegExpValidator embedded validator that can be used to match text input against a regular expression. The text input, passed as the input parameter, is taken from the received request body content $dataReceived{http_body}. The expression, defined using the expression input parameter checks to see that the content starts with REF- and ends with a sequence of one or more digits.

Step 6: Package the test suite

At this point you have made all necessary updates to your test suite. To recap, the structure of your test suite folder needs to match the following:

testSuite1
 |
 +-- artifacts
 |    |
 |    +-- PurchaseOrder.xsd
 |    +-- sample.xml
 |
 +-- testCase1.xml
 +-- testCase2.xml
 +-- testCase3.xml
 +-- testSuite.xml

To complete the creation of your test suite, ZIP the contents of the testSuite1 folder, without including the testSuite1 folder itself. Name the ZIP archive testSuite1_v2.zip (the resulting archive should match the one available here).

Your updated test suite is now ready to be uploaded to the test bed.

Summary

Congratulations! You just created a test suite that supports sending and receiving content. Through its test cases you learned how to use the GITB TDL’s messaging steps as well as new embedded handlers for HTTP messaging and string validation. You also saw an example of importing a sample file to send to the test system.

See also

As usual, make sure you check out the complete GITB TDL documentation for additional information on the GITB TDL and the possibilities you have in realising your testing needs.

A good next step from here would be to check out Guide: Defining your test configuration on how to setup the test suite on the test bed. If you don’t have a test bed instance to experiment with you can follow Guide: Installing the test bed to easily install one locally for development purposes.