Wednesday, December 30, 2020

Testing with Hoverfly and Java Part 5: XML and Xpath matchers

Previously we worked with some of the existing Hoverfly matchers like the regex, glob and exact.

Each one serves its purpose but we might want some rules that assist us with the format of the data exchanged through our requests.

On this blog we will focus on the matchers for xml.

Oracle Java Exam Prep, Oracle Java Tutorial and Material, Oracle Java Certification, Oracle Java Prep

The default xml matcher will compare the xml submitted with the xml expected. This means that the submitted xml shall be validated node by node value by value. New lines or any extra spaces as long as they don’t change the content that the xml carries will not prevent the request from being a success.

Let’s put our initial configuration that will make the xml match.

public static final String SUCCESS_RESPONSE = "<response>"
            + "<result>success</result>"
            + "</response>";
 
    private Hoverfly hoverfly;
 
    @BeforeEach
    void setUp() {
        var simulation = SimulationSource.dsl(service("http://localhost:8085")
                .post("/xml")
                .body(RequestFieldMatcher.newXmlMatcher("<document type=\"xml\">"
                        + "xml-request"
                        + "</document>"))
                .willReturn(success(SUCCESS_RESPONSE, "application/xml")));
 
        var localConfig = HoverflyConfig.localConfigs().disableTlsVerification().asWebServer().proxyPort(8085);
        hoverfly = new Hoverfly(localConfig, SIMULATE);
        hoverfly.start();
        hoverfly.simulate(simulation);
    }
 
    @AfterEach
    void tearDown() {
        hoverfly.close();
    }

So in our first example we will try to match the xml of our request with the xml expected.

@Test
    void testXmlExactMatch() {
        var client = HttpClient.newHttpClient();
 
        var exactRequest = HttpRequest.newBuilder()
                .uri(URI.create("http://localhost:8085/xml"))
                .POST(HttpRequest.BodyPublishers.ofString("  <document type=\"xml\">\n\n"
                        + "xml-request"
                        + "</document>\t"))
                .build();
 
        var exactResponse = client.sendAsync(exactRequest, HttpResponse.BodyHandlers.ofString())
                .thenApply(HttpResponse::body)
                .join();
 
        Assertions.assertEquals(SUCCESS_RESPONSE, exactResponse);
    }

As you see regardless of the new lines and the tabs, our request will be successful since the xml data do match.

Now let’s try to add a node to the xml.

@Test
    void testXmlNoMatch() {
        var client = HttpClient.newHttpClient();
 
        var exactRequest = HttpRequest.newBuilder()
                .uri(URI.create("http://localhost:8085/xml"))
                .POST(HttpRequest.BodyPublishers.ofString("  <document type=\"xml\">\n\n"
                        + "xml-request"
                        + "</document>\t<empty-node>ok</empty-node>"))
                .build();
 
        var exactResponse = client.sendAsync(exactRequest, HttpResponse.BodyHandlers.ofString())
                .join();
 
        Assertions.assertEquals(502, exactResponse.statusCode());
    }

The xml does not match thus it will fail.

Oracle Java Exam Prep, Oracle Java Tutorial and Material, Oracle Java Certification, Oracle Java Prep
Let’s focus to another problem. Since the data exchanged are dynamic, chances are that exact matches might not be possible. Also you might not need to focus on all the information submitted but just a specific section of the information exchanged. Therefore an XPath matcher becomes handy.

Will enhance the initial setup with an XPath rule.

@BeforeEach
    void setUp() {
        var simulation = SimulationSource.dsl(service("http://localhost:8085")
                .post("/xml")
                .body(RequestFieldMatcher.newXmlMatcher("<document type=\"xml\">"
                        + "xml-request"
                        + "</document>"))
                .willReturn(success(SUCCESS_RESPONSE, "application/xml"))
                .post("/xpath")
                .body(RequestFieldMatcher.newXpathMatcher("/document/payment[amount=1]"))
                .willReturn(success(SUCCESS_RESPONSE, "application/xml"))
        );
 
        var localConfig = HoverflyConfig.localConfigs().disableTlsVerification().asWebServer().proxyPort(8085);
        hoverfly = new Hoverfly(localConfig, SIMULATE);
        hoverfly.start();
        hoverfly.simulate(simulation);
    }

If there is a document node with a payment node and the value on the amount node is 1 there will be a match

Let’s go for a positive scenario

@Test
    void testXpathMatch() {
        var client = HttpClient.newHttpClient();
 
        var exactRequest = HttpRequest.newBuilder()
                .uri(URI.create("http://localhost:8085/xpath"))
                .POST(HttpRequest.BodyPublishers.ofString("  <document type=\"xml\">\n\n"
                        + "<payment><amount>142</amount></payment>"
                        + "<payment><amount>1</amount><currency>GBP</currency></payment>"
                        + "<payment>invalid</payment>"
                        + "</document>\t"))
                .build();
 
        var exactResponse = client.sendAsync(exactRequest, HttpResponse.BodyHandlers.ofString())
                .thenApply(HttpResponse::body)
                .join();
 
        Assertions.assertEquals(SUCCESS_RESPONSE, exactResponse);
    }

As expected we got a match.

Let’s go for a negative scenario.

@Test
    void testXpathNoMatch() {
        var client = HttpClient.newHttpClient();
 
        var exactRequest = HttpRequest.newBuilder()
                .uri(URI.create("http://localhost:8085/xpath"))
                .POST(HttpRequest.BodyPublishers.ofString("  <document type=\"xml\">\n\n"
                        + "<payment><amount>142</amount></payment>"
                        + "<payment><amount>no-match</amount><currency>GBP</currency></payment>"
                        + "<payment>invalid</payment>"
                        + "</document>\t"))
                .build();
 
        var exactResponse = client.sendAsync(exactRequest, HttpResponse.BodyHandlers.ofString())
                .join();
 
        Assertions.assertEquals(502, exactResponse.statusCode());
    }

That’s it we did use the xml and xpath matchers for the xml based data.

Related Posts

0 comments:

Post a Comment