2
\$\begingroup\$

I have a need to try to automate the testing of a large Web Service with an XML API interface. The framework takes the form of a Mavenised Java project.

The usual maxims apply: must be highly extendable, maintainable and ideally will be relatively data driven: requirement to parameterize the tests to accept different inputs passed into XML requests to the API.

The responses from the API (xml) need to be parsed and values read using XPath then asserted against using TestNG.

I have a working model with one sample test. This uses a type of PageObject pattern where I plan to map the different xml requests to the API as business objects. It also uses RestAssurred to try and enforce some common language usage in a DSL. Because RestAssurred is primarily for REST services, there is a need to do some extra work with the request/reponse bodies to allow us to leverage RestAssurred.

I am primarily interested in how this framework can be improved, made more simple, more robust - perhaps using JavaBeans to set common standards. How can we improve in the way we send and receive the XML requests and responses which I see as potentially fallible?

Here is the basic structure:-

TestNG 'driver' file:-

<test name="workplace-test">

    <!--Build Post URL from the following-->
    <parameter name="protocol" value="http://"/>
    <parameter name="env" value="abc-qa-1"/>
    <parameter name="target" value="production"/>
    <parameter name="port" value="8080"/>
    <parameter name="endPoint" value="AbcBook"/>

    <!--Business User login-->
    <parameter name="businessUserLogin" value="ABCTEST"/>
    <parameter name="businessUserPassword" value="Iq7ShAIR5"/>

    <!--tests to run-->
    <classes>
        <class name="com.workplace.abc.api.FirstTest"/>
    </classes>
</test>

Base Test Class:

package com.workplace.abc.framework;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Parameters;


public class TestBase {

private String uri;
public Logger APPLICATION_LOGS = LoggerFactory.getLogger(getClass());

public String getUri() {
    return uri;
}

@BeforeClass
@Parameters({"protocol", "env", "target", "port", "endPoint"})
public void initialiseURI(String protocol, String env, String target, String port, String endPoint) {
    uri = protocol + env + "." + target + ".mcom:" + port + "/" + endPoint;
    APPLICATION_LOGS.debug("Will use the following URI: " + uri);
    }
}

Sample First Test:

package com.workplace.ABC.api;

import com.workplace.ABC.businessobjects.ABCRequestObject;
import com.workplace.ABC.framework.TestBase;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import static com.jayway.restassured.RestAssured.baseURI;
import static com.jayway.restassured.RestAssured.given;
import static com.jayway.restassured.RestAssured.when;
import static org.testng.AssertJUnit.assertEquals;

public class FirstTest extends TestBase {

private ABCRequestObject ABCControlRequestObject;

@BeforeClass
public void setUp() {
    ABCControlRequestObject = new ABCRequestObject();
    baseURI = getUri();
}

@Test
public void checkApiUp() {
    when().post().then().statusCode(200);
}

@Test(dependsOnMethods = "checkApiUp")
@Parameters({"businessUserLogin", "businessUserPassword"})
public void canCreateNewSessionAsAbusinessUser(String businessUserLogin, String businessUserPassword) {

    //@Given: I log in as Business User
    ABCControlRequestObject.withBusinessUserLogin(businessUserLogin);
    ABCControlRequestObject.withBusinessUserPassword(businessUserPassword);

    String request = ABCControlRequestObject.getControlRequestBody();

    //@When I request to create a new ABC session
    String response = given().
            when().
            request().
            contentType("text/xml").
            body(request).
            when().post().andReturn().asString();

    String ABCControlResponseMessage = ABCControlRequestObject.getControlResponseMessage(response);
    String ABCSessionID = ABCControlRequestObject.getSessionID(response);

    //@Then: I receive a success message from ABC
    assertEquals("true", ABCControlResponseMessage);
    System.out.println("-----------" + ABCControlResponseMessage + "------------");
    System.out.println("-----------" + ABCSessionID + "------------");
    APPLICATION_LOGS.debug("XML extracted from API: " + ABCControlResponseMessage);
    }
}

Page (Business) Object:

package com.workplace.ABC.businessobjects;

import com.workplace.ABC.framework.XmlUtilityObjects;
import org.w3c.dom.Document;

public class ABCRequestObject extends XmlUtilityObjects {

    private String businessUserID;
    private String businessUserPassword;
    private String baseURI;

    private String controlResponseMessage = "//*[local-name()=\"ControlResponse\"]/@Success";
    private String ABCSessionID = "//*[local-name()=\"SessionInfo\"]/@ABCSessionId";

    public ABCRequestObject() {

    }

    public ABCRequestObject withBusinessUserLogin(String id) {
        this.businessUserID = id;
        return this;
    }

    public ABCRequestObject withBusinessUserPassword(String password) {
        this.businessUserPassword = password;
        return this;
    }

    public ABCRequestObject withBaseURI(String baseURI) {
        this.baseURI = baseURI;
        return this;
    }

    public String getControlRequestBody() {
        String requestBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<ABC_ControlRQ xmlns=\"http://www.webaddress.com/ABC/2002/09\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" Target=\"test\" Version=\"2002A\" xsi:type=\"ABC_ControlRQ\">\n" +
                "<BusinessUserInfo BusinessUserId=\"" + getLoginId() + "\"" + " BusinessUserPassword=\"" + getBusinessUserPassword() + "\"/>\n" +
                "<SessionInfo CreateNewSession=\"true\"/>\n" +
                "<ControlRequest DeleteSession=\"false\"/>\n" +
                "</ABC_ControlRQ>";

        return requestBody;
    }

    public Document getParsedResponse(String response) {
        return parseResponse(response);
    }

    public String getControlResponseMessage(String response) {
        Document doc = getParsedResponse(response);
        return getNodeValue(doc, controlResponseMessage);
    }

    public String getSessionID(String response) {
        Document doc = getParsedResponse(response);
        return getNodeValue(doc, ABCSessionID);
    }

    public String getBusinessUserID() {
        return businessUserID;
    }

    public String getLoginId() {
        return BusinessUserID;
    }

    public String getBusinessUserPassword() {
        return businessUserPassword;
    }

    public String getBaseURI() {
        return baseURI;
    }

}

Utility Class:

package com.workplace.ABC.framework;

import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;
import java.io.IOException;
import java.io.StringReader;

public class XmlUtilityObjects {

private XPath xpath;

public XmlUtilityObjects() {
    XPathFactory xPathFactory = XPathFactory.newInstance();
    this.xpath = xPathFactory.newXPath();
}

public Document parseResponse(String response) {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(true);
    DocumentBuilder builder;
    Document doc = null;

    try {
        builder = factory.newDocumentBuilder();
        doc = builder.parse(new InputSource((new StringReader(response))));

    } catch (ParserConfigurationException | org.xml.sax.SAXException | IOException e) {
        e.printStackTrace();
    }
    return doc;
}


public String getNodeValue(Document doc, String locator) {
    String nodeValue = null;
    try {
        XPathExpression e = this.xpath.compile(locator);
        nodeValue = (String)e.evaluate(doc, XPathConstants.STRING);
    } catch (XPathExpressionException e) {
        e.printStackTrace();
    }

    return nodeValue;
    }
}
\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.