MockRestServiceServer看到来自先前测试的请求



我正在使用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中的verifyreset不需要这些行(:

// remove this:
mockServer.reset(); // Added trying to fix the issue

最新更新