Spring MVC 测试框架因 HTTP 响应 406 而失败
Posted
技术标签:
【中文标题】Spring MVC 测试框架因 HTTP 响应 406 而失败【英文标题】:Spring MVC testframework fails with HTTP Response 406 【发布时间】:2012-12-16 22:36:09 【问题描述】:我开始使用 Spring 3.2 的新 MVC 测试框架,但我的所有测试用例都无法获得 406 个 HTTP 响应代码。
测试用例很简单
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());
对应的资源是
@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
我确定这是因为媒体类型错误,但我不知道原因。
失败的测试用例的踪迹:
java.lang.AssertionError:预期状态: 但原为: 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) 在 de.yourdelivery.rest.location.LocationResouceTest.testGetLocationByPlzPattern(LocationResouceTest.java:37) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 在 sun.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.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 在 org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) 在 org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) 在 org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 在 org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) 在 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.java: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) 在 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) 在 org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
【问题讨论】:
【参考方案1】:如果你有一个@Configuration
类,你可以添加
@987654321@
注解,而不是使用带有 <mvc:annotation-driven />
的 XML 配置。
【讨论】:
谢谢。这解决了我的问题。 谢谢,将@EnableWebMvc 添加到我的测试@Configuration
课程中成功了!
谢谢,终于找到我的问题了!!【参考方案2】:
这可能是由于在 Spring 测试上下文中没有任何 MVC 配置造成的。使用类似的东西时:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("/test-context.xml")
...那么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>
可以很容易地测试是否是上述问题,使用没有指定任何特殊内容的控制器(例如:@RequestMapping
中没有produces
),因此不需要任何内容协商:
@RequestMapping(value = "/foo", method = RequestMethod.GET)
@ResponseBody
public String getFoo()
return "bar";
...与:
@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 应该会输出许多错误消息,不是吗? 我不这么认为,@Raedwald。我在自己遇到 406 Unacceptable 之后发布了这个,然后找到了修复程序。不确定我是否有任何堆栈跟踪,但我对此表示怀疑。在初始化期间,我不明白为什么 Spring 在不知道它会收到什么请求时会为@RequestMapping
打印任何错误。在实际请求期间,它根本无法映射它;那里打印的错误不多?无法映射实际请求与请求未知 URL 或使用未映射的 HTTP 方法请求是一样的:没有太多其他内容的 HTTP 错误响应?【参考方案3】:
需要在spring xml中添加如下代码,在jackson中序列化POJO。
<annotation-driven />
【讨论】:
【参考方案4】:必须同时拥有@EnableWebMvc
和.accept(MediaType.APPLICATION_JSON)
【讨论】:
【参考方案5】:您在配置 xml 文件中缺少 <mvc:annotation-driven />
。
【讨论】:
合适的命名空间是 xmlns:mvc="springframework.org/schema/mvc"。【参考方案6】:我认为,spring 的做事方式是使用 HttpResponseEntity,或者返回一个模型和视图。 例如:
@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);
(我会对你取得的任何进一步进展感兴趣,因为它是全新的)
【讨论】:
好的,我检查了一下,仍然得到 406 响应。我改变了我的问题,删除了accept
方法
也试过了。结果与?someparam
和param("someparam", value)
相同
除了 406 之外我没有得到任何响应,所以没有 json ......但如果我卷曲它仍然可以工作【参考方案7】:
我认为解决方法是这样修改请求:
this.mockMvc.perform(get("/someurl?someparam=somevalue").contentType(MediaType.APPLICATION_JSON)).andExpect..
【讨论】:
我遇到了同样的问题并尝试了此线程中提供的方式。但仍然是 406。【参考方案8】:我刚才也遇到了同样的问题,通过将Controller的返回类型改为String来解决。 并直接返回 JSON 字符串而不是对象。它确实有效。
Gson gson = new Gson();
return gson.toJson(dto);
【讨论】:
以上是关于Spring MVC 测试框架因 HTTP 响应 406 而失败的主要内容,如果未能解决你的问题,请参考以下文章
使用 REST 模板和 JSON 响应格式在 Spring MVC 上返回 Http Status 500