Browse Source

Fix issue with xpath assertions in Spring Test MVC

Issue: SPR-10704
pull/317/merge
Rossen Stoyanchev 11 years ago
parent
commit
7bab879623
  1. 12
      spring-test-mvc/src/main/java/org/springframework/test/util/XpathExpectationsHelper.java
  2. 116
      spring-test-mvc/src/test/java/org/springframework/test/web/servlet/samples/standalone/resultmatchers/XpathAssertionTests.java

12
spring-test-mvc/src/main/java/org/springframework/test/util/XpathExpectationsHelper.java

@ -16,9 +16,6 @@ @@ -16,9 +16,6 @@
package org.springframework.test.util;
import static org.springframework.test.util.AssertionErrors.*;
import static org.springframework.test.util.MatcherAssertionErrors.*;
import java.io.StringReader;
import java.util.Collections;
import java.util.Map;
@ -33,12 +30,16 @@ import javax.xml.xpath.XPathExpressionException; @@ -33,12 +30,16 @@ import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.hamcrest.Matcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.xml.SimpleNamespaceContext;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import static org.springframework.test.util.AssertionErrors.*;
import static org.springframework.test.util.MatcherAssertionErrors.*;
/**
* A helper class for applying assertions via XPath expressions.
*
@ -51,6 +52,8 @@ public class XpathExpectationsHelper { @@ -51,6 +52,8 @@ public class XpathExpectationsHelper {
private final XPathExpression xpathExpression;
private final boolean hasNamespaces;
/**
* Class constructor.
@ -66,6 +69,7 @@ public class XpathExpectationsHelper { @@ -66,6 +69,7 @@ public class XpathExpectationsHelper {
this.expression = String.format(expression, args);
this.xpathExpression = compileXpathExpression(this.expression, namespaces);
this.hasNamespaces = !CollectionUtils.isEmpty(namespaces);
}
private XPathExpression compileXpathExpression(String expression, Map<String, String> namespaces)
@ -104,7 +108,7 @@ public class XpathExpectationsHelper { @@ -104,7 +108,7 @@ public class XpathExpectationsHelper {
*/
protected Document parseXmlString(String xml) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setNamespaceAware(this.hasNamespaces);
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
InputSource inputSource = new InputSource(new StringReader(xml));
Document document = documentBuilder.parse(inputSource);

116
spring-test-mvc/src/test/java/org/springframework/test/web/servlet/samples/standalone/resultmatchers/XpathAssertionTests.java

@ -16,17 +16,6 @@ @@ -16,17 +16,6 @@
package org.springframework.test.web.servlet.samples.standalone.resultmatchers;
import static org.hamcrest.Matchers.closeTo;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -47,6 +36,12 @@ import org.springframework.test.web.servlet.MockMvc; @@ -47,6 +36,12 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
import static org.springframework.web.bind.annotation.RequestMethod.*;
/**
* Examples of expectations on XML response content with XPath expressions.
*
@ -57,7 +52,7 @@ import org.springframework.web.bind.annotation.ResponseBody; @@ -57,7 +52,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
*/
public class XpathAssertionTests {
private static final Map<String, String> NS =
private static final Map<String, String> musicNamespace =
Collections.singletonMap("ns", "http://example.org/music/people");
private MockMvc mockMvc;
@ -78,13 +73,13 @@ public class XpathAssertionTests { @@ -78,13 +73,13 @@ public class XpathAssertionTests {
String performer = "/ns:people/performers/performer[%s]";
this.mockMvc.perform(get("/music/people"))
.andExpect(xpath(composer, NS, 1).exists())
.andExpect(xpath(composer, NS, 2).exists())
.andExpect(xpath(composer, NS, 3).exists())
.andExpect(xpath(composer, NS, 4).exists())
.andExpect(xpath(performer, NS, 1).exists())
.andExpect(xpath(performer, NS, 2).exists())
.andExpect(xpath(composer, NS, 1).node(notNullValue()));
.andExpect(xpath(composer, musicNamespace, 1).exists())
.andExpect(xpath(composer, musicNamespace, 2).exists())
.andExpect(xpath(composer, musicNamespace, 3).exists())
.andExpect(xpath(composer, musicNamespace, 4).exists())
.andExpect(xpath(performer, musicNamespace, 1).exists())
.andExpect(xpath(performer, musicNamespace, 2).exists())
.andExpect(xpath(composer, musicNamespace, 1).node(notNullValue()));
}
@Test
@ -94,11 +89,11 @@ public class XpathAssertionTests { @@ -94,11 +89,11 @@ public class XpathAssertionTests {
String performer = "/ns:people/performers/performer[%s]";
this.mockMvc.perform(get("/music/people"))
.andExpect(xpath(composer, NS, 0).doesNotExist())
.andExpect(xpath(composer, NS, 5).doesNotExist())
.andExpect(xpath(performer, NS, 0).doesNotExist())
.andExpect(xpath(performer, NS, 3).doesNotExist())
.andExpect(xpath(composer, NS, 0).node(nullValue()));
.andExpect(xpath(composer, musicNamespace, 0).doesNotExist())
.andExpect(xpath(composer, musicNamespace, 5).doesNotExist())
.andExpect(xpath(performer, musicNamespace, 0).doesNotExist())
.andExpect(xpath(performer, musicNamespace, 3).doesNotExist())
.andExpect(xpath(composer, musicNamespace, 0).node(nullValue()));
}
@Test
@ -108,15 +103,15 @@ public class XpathAssertionTests { @@ -108,15 +103,15 @@ public class XpathAssertionTests {
String performerName = "/ns:people/performers/performer[%s]/name";
this.mockMvc.perform(get("/music/people"))
.andExpect(xpath(composerName, NS, 1).string("Johann Sebastian Bach"))
.andExpect(xpath(composerName, NS, 2).string("Johannes Brahms"))
.andExpect(xpath(composerName, NS, 3).string("Edvard Grieg"))
.andExpect(xpath(composerName, NS, 4).string("Robert Schumann"))
.andExpect(xpath(performerName, NS, 1).string("Vladimir Ashkenazy"))
.andExpect(xpath(performerName, NS, 2).string("Yehudi Menuhin"))
.andExpect(xpath(composerName, NS, 1).string(equalTo("Johann Sebastian Bach"))) // Hamcrest..
.andExpect(xpath(composerName, NS, 1).string(startsWith("Johann")))
.andExpect(xpath(composerName, NS, 1).string(notNullValue()));
.andExpect(xpath(composerName, musicNamespace, 1).string("Johann Sebastian Bach"))
.andExpect(xpath(composerName, musicNamespace, 2).string("Johannes Brahms"))
.andExpect(xpath(composerName, musicNamespace, 3).string("Edvard Grieg"))
.andExpect(xpath(composerName, musicNamespace, 4).string("Robert Schumann"))
.andExpect(xpath(performerName, musicNamespace, 1).string("Vladimir Ashkenazy"))
.andExpect(xpath(performerName, musicNamespace, 2).string("Yehudi Menuhin"))
.andExpect(xpath(composerName, musicNamespace, 1).string(equalTo("Johann Sebastian Bach"))) // Hamcrest..
.andExpect(xpath(composerName, musicNamespace, 1).string(startsWith("Johann")))
.andExpect(xpath(composerName, musicNamespace, 1).string(notNullValue()));
}
@Test
@ -125,12 +120,12 @@ public class XpathAssertionTests { @@ -125,12 +120,12 @@ public class XpathAssertionTests {
String composerDouble = "/ns:people/composers/composer[%s]/someDouble";
this.mockMvc.perform(get("/music/people"))
.andExpect(xpath(composerDouble, NS, 1).number(21d))
.andExpect(xpath(composerDouble, NS, 2).number(.0025))
.andExpect(xpath(composerDouble, NS, 3).number(1.6035))
.andExpect(xpath(composerDouble, NS, 4).number(Double.NaN))
.andExpect(xpath(composerDouble, NS, 1).number(equalTo(21d))) // Hamcrest..
.andExpect(xpath(composerDouble, NS, 3).number(closeTo(1.6, .01)));
.andExpect(xpath(composerDouble, musicNamespace, 1).number(21d))
.andExpect(xpath(composerDouble, musicNamespace, 2).number(.0025))
.andExpect(xpath(composerDouble, musicNamespace, 3).number(1.6035))
.andExpect(xpath(composerDouble, musicNamespace, 4).number(Double.NaN))
.andExpect(xpath(composerDouble, musicNamespace, 1).number(equalTo(21d))) // Hamcrest..
.andExpect(xpath(composerDouble, musicNamespace, 3).number(closeTo(1.6, .01)));
}
@Test
@ -139,20 +134,36 @@ public class XpathAssertionTests { @@ -139,20 +134,36 @@ public class XpathAssertionTests {
String performerBooleanValue = "/ns:people/performers/performer[%s]/someBoolean";
this.mockMvc.perform(get("/music/people"))
.andExpect(xpath(performerBooleanValue, NS, 1).booleanValue(false))
.andExpect(xpath(performerBooleanValue, NS, 2).booleanValue(true));
.andExpect(xpath(performerBooleanValue, musicNamespace, 1).booleanValue(false))
.andExpect(xpath(performerBooleanValue, musicNamespace, 2).booleanValue(true));
}
@Test
public void testNodeCount() throws Exception {
this.mockMvc.perform(get("/music/people"))
.andExpect(xpath("/ns:people/composers/composer", NS).nodeCount(4))
.andExpect(xpath("/ns:people/performers/performer", NS).nodeCount(2))
.andExpect(xpath("/ns:people/composers/composer", NS).nodeCount(equalTo(4))) // Hamcrest..
.andExpect(xpath("/ns:people/performers/performer", NS).nodeCount(equalTo(2)));
.andExpect(xpath("/ns:people/composers/composer", musicNamespace).nodeCount(4))
.andExpect(xpath("/ns:people/performers/performer", musicNamespace).nodeCount(2))
.andExpect(xpath("/ns:people/composers/composer", musicNamespace).nodeCount(equalTo(4))) // Hamcrest..
.andExpect(xpath("/ns:people/performers/performer", musicNamespace).nodeCount(equalTo(2)));
}
// SPR-10704
@Test
public void testFeedWithLinefeedChars() throws Exception {
// Map<String, String> namespace = Collections.singletonMap("ns", "");
standaloneSetup(new BlogFeedController()).build()
.perform(get("/blog.atom").accept(MediaType.APPLICATION_ATOM_XML))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_ATOM_XML))
.andExpect(xpath("//feed/title").string("Test Feed"))
.andExpect(xpath("//feed/icon").string("http://www.example.com/favicon.ico"));
}
@Controller
private static class MusicController {
@ -203,4 +214,19 @@ public class XpathAssertionTests { @@ -203,4 +214,19 @@ public class XpathAssertionTests {
}
}
@Controller
public class BlogFeedController {
@RequestMapping(value="/blog.atom", method = { GET, HEAD })
@ResponseBody
public String listPublishedPosts() {
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
+ "<feed xmlns=\"http://www.w3.org/2005/Atom\">\r\n"
+ " <title>Test Feed</title>\r\n"
+ " <icon>http://www.example.com/favicon.ico</icon>\r\n"
+ "</feed>\r\n\r\n";
}
}
}

Loading…
Cancel
Save