使用 MockRestServiceServer 时无法精确测试服务调用次数
Posted
技术标签:
【中文标题】使用 MockRestServiceServer 时无法精确测试服务调用次数【英文标题】:When using MockRestServiceServer cannot precisely test number of service calls 【发布时间】:2019-02-21 18:19:45 【问题描述】:我正在为服务调用编写一些重试逻辑,并尝试在单元测试中测试 Rest Template 是否尝试命中服务一定次数。我正在使用以下代码来执行测试。
MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build();
mockServer.expect(ExpectedCount.times(5), method(HttpMethod.GET))
.andRespond(withServerError());
service.call();
我将重试逻辑设置为仅进行两次尝试。上面的测试代码要求它发生五次,但测试总是通过。事实上,我可以让这个测试失败的唯一方法是将预期计数设置为 1(任何小于实际调用次数的值)。当我使用ExpectedCount.min
或ExpectedCount.between
时会出现同样的问题,因为只有在实际调用超出预期时测试才会失败。
我需要能够测试确切数量的服务调用,最好不使用 Mockito。
【问题讨论】:
【参考方案1】:这是最终对我有用的方法,最多尝试 4 次:
MockRestServiceServer server;
@Before
public void setUp()
server = MockRestServiceServer.bindTo(restTemplate).build();
@After
public void serverVerify()
server.verify();
@Test
public void doWork_retryThenSuccess() throws Exception
final String responseBody = "<some valid response JSON>";
final String url = BASE_URL + "/doWork";
server.expect(requestTo(url))
.andExpect(MockRestRequestMatchers.method(HttpMethod.POST))
.andRespond(ExceptionResponseCreator.withException(new SocketTimeoutException("first")));
server.expect(requestTo(url))
.andExpect(MockRestRequestMatchers.method(HttpMethod.POST))
.andRespond(ExceptionResponseCreator.withException(new IOException("second")));
server.expect(requestTo(url))
.andExpect(MockRestRequestMatchers.method(HttpMethod.POST))
.andRespond(ExceptionResponseCreator.withException(new RemoteAccessException("third")));
server.expect(requestTo(url))
.andExpect(MockRestRequestMatchers.method(HttpMethod.POST))
.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));
final MyResponseClass response = myService.call();
assertThat(response, notNullValue());
// other asserts here...
我们被限制使用 Spring Test 5.0.10,它没有MockRequestResponseCreators.withException()
(方法是在 5.2.2 中添加的)。借用 Spring 5.2.7 代码,效果很好:
package com.company.test;
import java.io.IOException;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.test.web.client.ResponseCreator;
import org.springframework.test.web.client.response.MockRestResponseCreators;
public class ExceptionResponseCreator extends MockRestResponseCreators
public static ResponseCreator withException(IOException ex)
return request -> throw ex; ;
public static ResponseCreator withException(RemoteAccessException ex)
return request -> throw ex; ;
【讨论】:
【参考方案2】:您需要在提出所有请求后致电mockServer.verify()
,以检查是否符合预期。否则,您可以从不提出任何请求而侥幸逃脱。
【讨论】:
【参考方案3】:您可以使用所需的逻辑创建自己的 ResponseCreator。例如:
class DelegateResponseCreator implements ResponseCreator
private final ResponseCreator[] delegates;
private int toExecute = 0;
public DelegateResponseCreator(final ResponseCreator... delegates)
this.delegates = delegates;
@Override
public ClientHttpResponse createResponse(final ClientHttpRequest request) throws IOException
ClientHttpResponse ret = this.delegates[this.toExecute % this.delegates.length].createResponse(request);
this.toExecute++;
return ret;
这个委托按顺序执行 ResponseDelegates。
所以你可以模拟你想要的电话号码的响应
mockServer.expect(ExpectedCount.times(5), MockRestRequestMatchers.method(HttpMethod.GET))
.andRespond(new DelegateResponseCreator(
MockRestResponseCreators.withServerError(),
MockRestResponseCreators.withServerError(),
MockRestResponseCreators.withServerError(),
MockRestResponseCreators.withServerError(),
MockRestResponseCreators.withSuccess()
));
在此示例中,前四个调用将返回服务器错误,而第五个调用将成功。
【讨论】:
检查 zed 的答案是否准确。以上是关于使用 MockRestServiceServer 时无法精确测试服务调用次数的主要内容,如果未能解决你的问题,请参考以下文章
如何在 MockRestServiceServer 中模拟 http 标头?
如何在 MockRestServiceServer 中通过字符串模式期待 requestTo?
Spring MockRestServiceServer 处理多个异步请求
由于未绑定的 RestTemplate,Spring-Boot RestClientTest 无法正确自动配置 MockRestServiceServer