我正在使用MockRestServiceServer
运行JUnit5,并看到当我使用异步请求运行多个测试时,测试A中的MockRestServiceServer
将看到来自测试B的请求,并将其标记为意外。
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class MyTestClass {
@Autowired
private RestTemplate restTemplate;
@Autowired
private WebApplicationContext wac;
private MockRestServiceServer mockServer;
private MockMvc mockMvc;
private URI asyncUri = URI.create("/asyncUrl");
@BeforeEach
public void setUp(){
mockerServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build();
mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@AfterEach
public void tearDown(){
mockServer.verify();
mockServer.reset();
}
@Test
public void dontRunAsyncMethod(){
mockServer.reset(); // Added trying to fix the issue
mockServer.expect(ExpectedCount.never(), requestTo(asyncUri));
URI uri = URI.create("/myApi?runAsyncMethod=false");
mockMvc.perform(get(uri));
}
@Test
public void doRunAsyncMethod(){
mockServer.reset(); // Added trying to fix the issue
// Side issue here - I have to use `between` rather than `times`
// because mockServer validates before request happens
mockServer.expect(ExpectedCount.between(0, 1), requestTo(asyncUri));
URI uri = URI.create("/myApi?runAsyncMethod=true");
mockMvc.perform(get(uri));
}
}
当分别运行时,两个测试都通过了。但是,当我一起运行它们时,dontRunAsyncMethod
将失败,表示不希望向/asyncUrl
发出请求。有没有一种方法可以更有效地分离测试?我能以某种方式确保在开始下一次测试之前完成所有请求吗?
您的注释本身提供了一个提示:
// Side issue here - I have to use `between` rather than `times` // because mockServer validates before request happens
这实际上是问题;测试不等待在后台进行的异步调用。
首先,这个断言应该被更正为times(1)
,因为在这个测试中进行0次异步调用是不正确的。通过允许它断言可以进行0次调用,异步行为的测试只是通过了没有指定正确的行为。
现在,这个测试在调用之前完成(如果times(1)
的断言正确,则会失败(,这与以下事实直接相关:如果两个测试都运行,则另一个测试的异步调用是而不是。两者的原因都是异步测试没有等待异步调用异步发生:所以调用在某个时候在后台触发,但直到一个测试完成,JUnit转到另一个测试。
解决方法应该是确保测试等待异步处理。希望这样的东西能起作用(假设/myApi
实现中的异步机制与这里讨论的机制相同(:
@Test
public void doRunAsyncMethod(){
mockServer.expect(ExpectedCount.times(1), requestTo(asyncUri));
URI uri = URI.create("/myApi?runAsyncMethod=true");
MvcResult mvcCall = mockMvc.perform(get(uri))
.andExpect(status().isOk())
.andExpect(request().asyncStarted())
.andExpect(request().asyncResult("expected response here"))
.andReturn();
mockMvc.perform(asyncDispatch(mvcCall))
.andExpect(status().isOk())
.andExpect(content().string("expected response here"));
}
(您必须调整响应主体,如果您的响应状态不正常,则删除这些行或将其更改为预期状态。从文档中,我还不清楚这些预期集合中的哪一组是指您正在测试的对/myApi
的调用的响应,哪一组指的是mockServer.expect(ExpectedCount.times(1), requestTo(asyncUri));
的响应,而我没有看到CCD_1的实现0,所以我在这里能做的最好的事情就是模仿文档。您可以查找asyncResult
的JavaDocs,看看是否有一个版本的响应正文为空/没有,如果您的响应根本不应该包含内容。(
此外,如果非异步测试导致进行异步调用,但因为它没有等待最初不应该发生的异步进程,所以该测试仍然通过了调用never
的断言,该怎么办?(在所有时间的意义上并不是真正的"从不",而是在测试运行时的0调用计数!(为了避免这种情况,我们还需要断言该测试的请求没有运行异步活动:
@Test
public void dontRunAsyncMethod(){
mockServer.expect(ExpectedCount.never(), requestTo(asyncUri));
URI uri = URI.create("/myApi?runAsyncMethod=false");
mockMvc.perform(get(uri))
.andExpect(request().asyncNotStarted());
}
顺便说一句,您可以在每次测试开始时删除行(@AfterEach
中的verify
和reset
不需要这些行(:
// remove this:
mockServer.reset(); // Added trying to fix the issue