简体   繁体   English

Spring MVC testframework因HTTP Response 406而失败

[英]Spring MVC testframework fails with HTTP Response 406

I started to use the new MVC Testframework of Spring 3.2 and got stuck with getting 406 HTTP Response Codes for all my test cases. 我开始使用Spring 3.2的新MVC Testframework,并且无法为我的所有测试用例获取406个HTTP响应代码。

The testcase is plain simple 测试用例很简单

public class LocationResouceTest {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
    }

    @Test
    public void testGetLocationByPlzPattern() throws Exception {
        // here I need to define the media type as a static var from MediaType
        this.mockMvc.perform(get("/someurl?someparam=somevalue")).andExpect(status().isOk());
    }

}

the corresponding resource is 相应的资源是

@Controller
// here I need to define the media type as string
@RequestMapping(value = "/someurl", produces = "application/json; charset=UTF-8")
public class LocationResource {

    @ResponseBody
    @RequestMapping(method = RequestMethod.GET)
    public ArrayList<DTO> getAllIndex(@RequestParam("someparam") String param) {
        return ... //the list of DTO classes is transformed to json just fine if called with curl
    }

}

I am sure it is because of a wrong media type but I cannot figure out why. 我确信这是因为媒体类型不对,但我无法弄清楚原因。

The trace of the failing testcase: 失败的测试用例的痕迹:

java.lang.AssertionError: Status expected:<200> but was:<406> at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:60) at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:89) at org.springframework.test.web.servlet.result.StatusResultMatchers$5.match(StatusResultMatchers.java:546) at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:141) at de.yourdelivery.rest.location.LocationResouceTest.testGetLocationByPlzPattern(LocationResouceTest.java:37) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runn java.lang.AssertionError:状态预期:<200>但:<406>在org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:60)在org.springframework.test.util.AssertionErrors.assertEquals( AssertionErrors.java:89)在org.springframework.test.web.servlet.result.StatusResultMatchers $ 5.match(StatusResultMatchers.java:546)在org.springframework.test.web.servlet.MockMvc $ 1.andExpect(MockMvc.java: 141)在sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)的sun.reflect.NativeMethodAccessorImpl.invoke0(本地方法)中的de.yourdelivery.rest.location.LocationResouceTest.testGetLocationByPlzPattern(LocationResouceTest.java:37) .reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)在java.lang.reflect.Method.invoke(Method.java:597)在org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall(FrameworkMethod.java:45)在org.junit.runn的org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) ers.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.j ers.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)在org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)在org.junit.internal.runners.statements.RunBefores.evaluate(在org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java: 83)在org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)在org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)在org.springframework .test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)在org.junit.runners.ParentRunner $ 3.run(ParentRunner.java:231)在org.junit.runners.ParentRunner $ 1.schedule(ParentRunner.java :60)在org.junit.runners.ParentRunner.runChildren(ParentRunner.j) ava:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTes AVA:229)在org.junit.runners.ParentRunner.access $ 000(ParentRunner.java:50)在org.junit.runners.ParentRunner $ 2.evaluate(ParentRunner.java:222)在org.springframework.test.context.junit4 .statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)at org.junit.runners.ParentRunner.run(ParentRunner.java) :300)在org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)在org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)的组织。 eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)在org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)在org.eclipse.jdt。 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTes)中的internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) tRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) tRunner.java:390)org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

如果您有@Configuration类,则可以添加@EnableWebMvc注释,而不是使用<mvc:annotation-driven />的XML配置。

This might be caused by not having any MVC configuration in the Spring test context. 这可能是由于Spring测试上下文中没有任何MVC配置引起的。 When using something like: 使用类似的东西时:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("/test-context.xml")

...then that test-context.xml file should also include things like: ...然后test-context.xml文件还应包含以下内容:

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager">
  <mvc:message-converters>
    <bean id="..." class=
"org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
    <bean id="..."
      class="org.springframework.http.converter.StringHttpMessageConverter"/>
    <bean id="..."
      class="org.springframework.http.converter.FormHttpMessageConverter"/>
  </mvc:message-converters>
</mvc:annotation-driven>

<bean id="contentNegotiationManager" 
  class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
  <property name="defaultContentType" value="application/json" />
  <property name="mediaTypes">
    <value>
      json=application/json
      xml=application/xml
    </value>
  </property>
</bean>

One can easily test if the above is the problem, with a controller that does not specify anything special (such as: no produces in @RequestMapping ), and hence does not need any content negotiation: 人们可以很容易地测试上面是否是问题,控制器没有指定任何特殊的东西(例如: @RequestMapping没有produces ),因此不需要任何内容​​协商:

@RequestMapping(value = "/foo", method = RequestMethod.GET)
@ResponseBody
public String getFoo() {
    return "bar";
}

...with: ...有:

@Test
public void getFoo() throws Exception {
    MvcResult result = 
      this.mockMvc.perform(get("/foo").accept(MediaType.TEXT_PLAIN))
        .andExpect(status().isOk())
        .andReturn();
    Assert.assertEquals(result.getResponse().getContentAsString(), "bar"); 
}

您需要将以下代码添加到spring xml以在jackson中序列化POJO。

<annotation-driven />

有必要同时拥有@EnableWebMvc.accept(MediaType.APPLICATION_JSON)

您缺少配置xml文件中的<mvc:annotation-driven />

The spring way of doing things is, i think, to use a HttpResponseEntity, or return a modelandview. 我认为,春天的做事方式是使用HttpResponseEntity,或者返回一个模式视图。 For example : 例如 :

@ResponseBody
ResponseEntity<String> getFoo() {
  HttpHeaders responseHeaders = new HttpHeaders();
  responseHeaders.setContentType(MediaType.APPLICATION_JSON);
  String test = "{\"foo\":{\"title\": \"Stack\"}}";
  return new ResponseEntity<String>(test, responseHeaders, HttpStatus.OK);
}

(I'd be interested in any further progress you make as its all pretty new) (我会对你所做的任何进一步的进展感兴趣,因为它是全新的)

我认为修复方法是以这种方式修改请求:

this.mockMvc.perform(get("/someurl?someparam=somevalue").contentType(MediaType.APPLICATION_JSON)).andExpect..

I met same problem just now, and is resolved by changing the return type of the Controller to String. 我刚才遇到了同样的问题,并通过将Controller的返回类型更改为String来解决。 And return a JSON string instead of an object directly. 并直接返回JSON字符串而不是对象。 It does works. 它确实有效。

Gson gson = new Gson();
return gson.toJson(dto);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM