使用 StreamingResponseBody 时 Spring MockMvc 第二次测试失败
我有一个简单的 Spring Boot 服务,它使用 StreamingResponseBody 来编写响应。 当使用 MockMvc 进行测试时,第一个测试给出了正确的响应,但第二个测试的响应主体为空。 然而,当我在测试中添加一点睡眠时间时,它们都会起作用。
这是我的控制器(Kotlin)
@RestController
class DummyController() {
@GetMapping()
fun streamIndex() =
ResponseEntity.ok()
.contentType(MediaType.TEXT_PLAIN)
.body(StreamingResponseBody { it.write("Hello world".toByteArray()) })
}
和我的测试:
@AutoConfigureMockMvc(print = MockMvcPrint.NONE)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class DummyControllerTest {
private val controller = DummyController()
private val mvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(GlobalExceptionHandler()).build()
@Test
fun test1() {
mvc.perform(get("/")).andExpect(status().isOk).andExpect(content().string("Hello world"))
}
@Test
fun test2() {
mvc.perform(get("/")).andExpect(status().isOk).andExpect(content().string("Hello world"))
}
}
第一个测试成功,第二个测试失败:
java.lang.AssertionError: Response content expected:<Hello world> but was:<>
然后,当我在测试中添加一点延迟时,它会起作用:
@Test
fun test2() {
mvc.perform(get("/")).andExpect(status().isOk)
.andDo { Thread.sleep(5) }
.andExpect(content().string("Hello world"))
}
这是 MockMvc 中的错误还是我的测试中缺少的东西?
预先感谢,
罗布
I have a simple Spring Boot service that uses StreamingResponseBody to write the response.
When testing this with MockMvc, the first test gives me the correct response, but the second one has an empty response body.
However, when I add a little sleep time to the test, they both work.
Here is my controller (Kotlin)
@RestController
class DummyController() {
@GetMapping()
fun streamIndex() =
ResponseEntity.ok()
.contentType(MediaType.TEXT_PLAIN)
.body(StreamingResponseBody { it.write("Hello world".toByteArray()) })
}
And my tests:
@AutoConfigureMockMvc(print = MockMvcPrint.NONE)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class DummyControllerTest {
private val controller = DummyController()
private val mvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(GlobalExceptionHandler()).build()
@Test
fun test1() {
mvc.perform(get("/")).andExpect(status().isOk).andExpect(content().string("Hello world"))
}
@Test
fun test2() {
mvc.perform(get("/")).andExpect(status().isOk).andExpect(content().string("Hello world"))
}
}
Thee first test succeeds, the second one fails with:
java.lang.AssertionError: Response content expected:<Hello world> but was:<>
Then when I add a little delay in the test it works:
@Test
fun test2() {
mvc.perform(get("/")).andExpect(status().isOk)
.andDo { Thread.sleep(5) }
.andExpect(content().string("Hello world"))
}
Is this a bug in MockMvc or something missing in my test?
Thanks in advance,
Rob
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要首先通过执行以下操作来获取异步结果,而不是添加延迟:
确保将其添加到两个测试中。
来源: https://github.com/spring-projects/spring-framework/blob/main/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/ AsyncTests.java @line 81
Instead of adding a delay, you will need to fetch the async result first by doing the following:
Make sure you add this to both tests.
Source: https://github.com/spring-projects/spring-framework/blob/main/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/AsyncTests.java @line 81
你的测试是错误的/奇怪的。您有
@SpringBootTest
在端口上启动应用程序,配置了@AutoConfigureMockMvc
并完全忽略所有这些。@SpringBootTest
中的组合甚至不起作用,因为您无法将RANDOM_PORT
与MockMvc
一起使用(仅适用于 MOCK 环境)。您可以使用MOCK
环境或切换到TestRestTemplate
/TestWebClient
进行测试。您可能解决了手动构建控制器并向该控制器手动注册
MockMvc
时遇到的问题。最后,您使用了一个异步请求,您也需要正确使用该请求。请参阅 异步Spring 参考指南中的测试。它还展示了使用
WebTestClient
进行测试的另一种方法,这是流响应的首选方法。简而言之,你的测试有点像弗兰肯斯坦测试。
我强烈建议以正确的方式使用这些技术并按如下方式重写您的测试。
此测试不会启动完整的容器,而只会启动 Web MVC 内容和控制器所需的内容。在测试中,异步结果现在也已正确解析和断言。总而言之,由于启动所需的东西减少了(除非启动的东西不多),它现在应该运行得更快。
Your test is wrong/weird. You have
@SpringBootTest
which starts an app on the port, have configured@AutoConfigureMockMvc
and totally ignore all of that.The combination in your
@SpringBootTest
wouldn't even work as you cannot useRANDOM_PORT
withMockMvc
(that only works with a MOCK environment). You either use theMOCK
environment or switch toTestRestTemplate
/TestWebClient
for testing.You probably worked around the issues you had with manually constructing a controller and manually registering
MockMvc
with that controller.Finally you are using an async request which you would need to consume properly as well. See async testing in the Spring Reference Guide. It also shows another way of testing using the
WebTestClient
which is preferred for streaming responses.In short your test is a bit af a frankenstein test.
I would strongly suggest to use the technologies in a proper way and rewrite your test as follows.
This test won't start a full blown container but only the Web MVC stuff and the stuff needed for your controller. In the tests the async result is now also properly parsed and asserted. All in all it should now also run a lot faster due to the reduced things needed to start (unless there wasn't much to start with).