【问题标题】:When using MockRestServiceServer cannot precisely test number of service calls使用 MockRestServiceServer 时无法精确测试服务调用次数
【发布时间】: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.minExpectedCount.between 时会出现同样的问题,因为只有在实际调用超出预期时测试才会失败。

我需要能够测试确切数量的服务调用,最好不使用 Mockito。

【问题讨论】:

    标签: rest spring-boot junit


    【解决方案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 的答案是否准确。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多