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.
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.
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. The next blog shall focus on the JSON based matchers.
| Published on Java Code Geeks with permission by Emmanouil Gkatziouras, partner at our JCG program. See the original article here: Testing with Hoverfly and Java Part 5: XML and Xpath matchers Opinions expressed by Java Code Geeks contributors are their own. |
Thank you!
We will contact you soon.
Emmanouil GkatziourasDecember 29th, 2020Last Updated: December 22nd, 2020

This site uses Akismet to reduce spam. Learn how your comment data is processed.