Response data missing in Spring MVC test

2019-08-14 11:31发布

I have a controller that writes to the ModelMap like this:

@Controller
@RequestMapping("/dataset")
public class DatasetController {

    @Autowired
    DatasetDao datasetDao;

    @RequestMapping(method = RequestMethod.GET)
    public String getDataset(@RequestParam String name, ModelMap model) {
        Dataset ds = datasetDao.get(name);
        model.addAttribute("response", new DatasetResponse(ds));
        return "Success";
    }

I want to write a test case that gets a dataset and then performs more actions based on its contents. But, I'm having trouble getting data out of the service. My test case so far is:

@Test
public void testProducesXml() throws Exception {
    mockMvc.perform(get("/dataset.xml").param("name", "foo"))
        .andDo(print())
        .andExpect(status().isOk())
        .andExpect(model().attribute("Response",
            hasProperty("name", is("foo"))))
        .andExpect(xpath("/dataset/name").string("foo"));
}

The model().attribute line passes, but the test fails at xpath with:

org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file.

Ultimately I'd like to get a copy of the DatasetResponse in my test function so I can do other things with it. I tried using andReturn(), but that fails for the same reason that xpath fails.

It turns out that even though there's a DatasetResponse in the model, the body of the response is empty:

ModelAndView:
    View name = Success
         View = null
    Attribute = Response
        value = org.vpac.web.model.response.DatasetResponse@457fdd58
       errors = []

MockHttpServletResponse:
       Status = 200
Error message = null
      Headers = {}
 Content type = null
         Body = 

However if I start the app in Tomcat and go to /dataset.xml?name=foo in my browser, I can see the data as XML.

So, why is the body empty, and how can I get a reference to the DatasetResponse? Edit Do I need to trigger the view to render the model, or something?

1条回答
叛逆
2楼-- · 2019-08-14 12:21

This came down to the test being misconfigured: my MVC config is split across two files, as specified in my web.xml file:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/mvc-dispatcher-servlet.xml 
        /WEB-INF/applicationContext.xml
    </param-value>
</context-param>

But following examples from elsewhere, I only had my test class annotated with:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("file:src/main/webapp/WEB-INF/applicationContext.xml")
@Transactional
public class DatasetTest {
    ...

Adding the missing mvc-dispatcher-servlet.xml fixes the problem:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration({
    "file:src/main/webapp/WEB-INF/mvc-dispatcher-servlet.xml",
    "file:src/main/webapp/WEB-INF/applicationContext.xml"})
@Transactional
public class DatasetTest {
    ...

Now the ModelAndView contain the objects that I return from the controller, and the body of the response is not empty. .andExpect(xpath works as expected, and I can get a copy of the response object with:

mockMvc.perform(...).andReturn().getModelAndView().getModel().get("Response");
查看更多
登录 后发表回答