Spring MVC 控制器测试失败,主体为空
Spring MVC controller test fails with empty body
我正在编写带有 spring 引导的小型 REST API 并尝试编写 MVC 测试。
不幸的是,当我从控制器收到空响应时,MVC 测试失败了。
控制器class:
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping
public ResponseEntity getMessage(){
ResponseEntity responseEntity = null;
try {
responseEntity = new ResponseEntity("Hello from: " + InetAddress.getLocalHost().getHostAddress(), HttpStatus.OK);
} catch (UnknownHostException e) {
e.printStackTrace();
}
return responseEntity;
}
}
MVC测试方法:
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(get("/test")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello from:")));
}
问题是我 content()
总是空的。
我尝试打印如下响应
MvcResult result = this.mockMvc.perform(get("/test")).andReturn();
String res = result.getResponse().getContentAsString();
这清楚地表明 res
是空的。
我还有一个 mockito 测试,它与正确的响应完美结合。
Mockito 测试:
@Test
public void greetingShouldReturnMessageFromService() throws Exception {
when(service.getMessage()).thenReturn(ResponseEntity.ok("Hello from:"));
}
MVC 测试的输出:
MockHttpServletRequest:
HTTP Method = GET
Request URI = /test
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = com.test.rest.controller.TestController$MockitoMock5340695
Method = com.test.rest.controller.TestController$MockitoMock5340695#getMessage()
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
MockHttpServletRequest:
HTTP Method = GET
Request URI = /test
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = com.test.rest.controller.TestController$MockitoMock5340695
Method = com.test.rest.controller.TestController$MockitoMock5340695#getMessage()
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
MockHttpServletRequest:
HTTP Method = GET
Request URI = /test
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = com.test.rest.controller.TestController$MockitoMock5340695
Method = com.test.rest.controller.TestController$MockitoMock5340695#getMessage()
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Response content
Expected: a string containing "Hello from:"
but: was ""
Expected :a string containing "Hello from:"
Actual :""
<Click to see difference>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:18)
at org.springframework.test.web.servlet.result.ContentResultMatchers.lambda$string(ContentResultMatchers.java:129)
at org.springframework.test.web.servlet.MockMvc.andExpect(MockMvc.java:196)
at com.test.rest.TestControllerMockTest.shouldReturnDefaultMessage(TestControllerMockTest.java:38)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:132)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:124)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:74)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod[=15=](ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke[=15=](ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:104)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod(TestMethodTestDescriptor.java:202)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:135)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute(DefaultLauncher.java:197)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
你在方法级别尝试过@RequestMapping吗?
示例:
@RequestMapping("/hello") //Changed here
public ResponseEntity getMessage(){
ResponseEntity responseEntity = null;
try {
responseEntity = new ResponseEntity("Hello from: " + InetAddress.getLocalHost().getHostAddress(), HttpStatus.OK);
} catch (UnknownHostException e) {
e.printStackTrace();
}
return responseEntity;
}
您需要将您现在访问的 url 更改为“/test/hello”。
我不确定,但是按照下面的方法修改后它起作用了。
@Test
public void shouldReturnDefaultMessage() throws Exception {
when(service.getMessage()).thenReturn(ResponseEntity.ok("Hello from:")); // Added this line
this.mockMvc.perform(get("/test")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello from:")));
}
在上面的方法中,我添加了when(service.getMessage()).thenReturn(ResponseEntity.ok("Hello from:"));
行,测试通过。
参考:https://spring.io/guides/gs/testing-web/
在本页末尾声明:
We use @MockBean to create and inject a mock for the GreetingService
(if you do not do so, the application context cannot start), and we
set its expectations using Mockito
.
我正在编写带有 spring 引导的小型 REST API 并尝试编写 MVC 测试。
不幸的是,当我从控制器收到空响应时,MVC 测试失败了。
控制器class:
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping
public ResponseEntity getMessage(){
ResponseEntity responseEntity = null;
try {
responseEntity = new ResponseEntity("Hello from: " + InetAddress.getLocalHost().getHostAddress(), HttpStatus.OK);
} catch (UnknownHostException e) {
e.printStackTrace();
}
return responseEntity;
}
}
MVC测试方法:
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(get("/test")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello from:")));
}
问题是我 content()
总是空的。
我尝试打印如下响应
MvcResult result = this.mockMvc.perform(get("/test")).andReturn();
String res = result.getResponse().getContentAsString();
这清楚地表明 res
是空的。
我还有一个 mockito 测试,它与正确的响应完美结合。
Mockito 测试:
@Test
public void greetingShouldReturnMessageFromService() throws Exception {
when(service.getMessage()).thenReturn(ResponseEntity.ok("Hello from:"));
}
MVC 测试的输出:
MockHttpServletRequest:
HTTP Method = GET
Request URI = /test
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = com.test.rest.controller.TestController$MockitoMock5340695
Method = com.test.rest.controller.TestController$MockitoMock5340695#getMessage()
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
MockHttpServletRequest:
HTTP Method = GET
Request URI = /test
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = com.test.rest.controller.TestController$MockitoMock5340695
Method = com.test.rest.controller.TestController$MockitoMock5340695#getMessage()
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
MockHttpServletRequest:
HTTP Method = GET
Request URI = /test
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = com.test.rest.controller.TestController$MockitoMock5340695
Method = com.test.rest.controller.TestController$MockitoMock5340695#getMessage()
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Response content
Expected: a string containing "Hello from:"
but: was ""
Expected :a string containing "Hello from:"
Actual :""
<Click to see difference>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:18)
at org.springframework.test.web.servlet.result.ContentResultMatchers.lambda$string(ContentResultMatchers.java:129)
at org.springframework.test.web.servlet.MockMvc.andExpect(MockMvc.java:196)
at com.test.rest.TestControllerMockTest.shouldReturnDefaultMessage(TestControllerMockTest.java:38)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:132)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:124)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:74)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod[=15=](ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke[=15=](ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:104)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod(TestMethodTestDescriptor.java:202)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:135)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute(DefaultLauncher.java:197)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
你在方法级别尝试过@RequestMapping吗?
示例:
@RequestMapping("/hello") //Changed here
public ResponseEntity getMessage(){
ResponseEntity responseEntity = null;
try {
responseEntity = new ResponseEntity("Hello from: " + InetAddress.getLocalHost().getHostAddress(), HttpStatus.OK);
} catch (UnknownHostException e) {
e.printStackTrace();
}
return responseEntity;
}
您需要将您现在访问的 url 更改为“/test/hello”。
我不确定,但是按照下面的方法修改后它起作用了。
@Test
public void shouldReturnDefaultMessage() throws Exception {
when(service.getMessage()).thenReturn(ResponseEntity.ok("Hello from:")); // Added this line
this.mockMvc.perform(get("/test")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello from:")));
}
在上面的方法中,我添加了when(service.getMessage()).thenReturn(ResponseEntity.ok("Hello from:"));
行,测试通过。
参考:https://spring.io/guides/gs/testing-web/
在本页末尾声明:
We use @MockBean to create and inject a mock for the GreetingService (if you do not do so, the application context cannot start), and we set its expectations using Mockito
.