java - 如何使用 junit mockito 覆盖匿名类重写方法

标签 java junit mockito

我有以下代码根据响应代码重试请求。

public class Sample {
    public static HttpClient getInstance() {
        HttpClientBuilder builder = HttpClients.custom();     
            builder.setServiceUnavailableRetryStrategy(new ServiceUnavailableRetryStrategy() {
                int waitPeriod = 200;

                @Override
                public boolean retryRequest(final HttpResponse response, final int executionCount,
                    final HttpContext context) {

                    int statusCode = response.getStatusLine().getStatusCode();
                    return ((statusCode == 429)&& (executionCount < 3));
                }

                @Override
                public long getRetryInterval() {
                    return waitPeriod;
                }
            });

        return builder.build();

    }
}

虽然我正在为这个 getInstance 方法编写单元测试,但是覆盖的方法 (retryRequest, getRetryInterval) 没有被覆盖。我如何编写单元测试来覆盖这些方法。 通过谷歌搜索,我发现我们可以使用 ArgumentCaptor。 我试过下面的代码,但它不起作用。

import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;

import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.ServiceUnavailableRetryStrategy;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HttpContext;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

@WebAppConfiguration
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:context.xml"})
@PrepareForTest({ HttpClients.class, Sample.class})
public class Sample {

    @Mock
    HttpClientBuilder clientBuilderMock;

    @Mock
    CloseableHttpClient clientMock;

    @Mock
    HttpResponse responseMock;

    @Mock
    HttpContext contextMock;

    @Mock
    StatusLine statusLineMock;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        PowerMockito.mockStatic(HttpClients.class);
    }

    @Test
    public void test() throws Exception {       
        when(HttpClients.custom()).thenReturn(clientBuilderMock);
        when(clientBuilderMock.build()).thenReturn(clientMock);
        when(responseMock.getStatusLine()).thenReturn(statusLineMock);
        when(statusLineMock.getStatusCode()).thenReturn(429);

        Sample.getInstance();

        ArgumentCaptor<ServiceUnavailableRetryStrategy> argumentCaptor = ArgumentCaptor.forClass(ServiceUnavailableRetryStrategy.class);
        verify(clientBuilderMock).setServiceUnavailableRetryStrategy(argumentCaptor.capture());
        ServiceUnavailableRetryStrategy retryStrategy = argumentCaptor.getValue();
        retryStrategy.retryRequest(responseMock, 3, contextMock);       
    }

}

argumentCaptor.capture() 总是给我 null。我越来越喜欢

org.mockito.exceptions.base.MockitoException: No argument value was captured! You might have forgotten to use argument.capture() in verify()... ...or you used capture() in stubbing but stubbed method was not called. Can anyone help me on this. I would like to test the retryRequest method functionality.

最佳答案

编辑:改写答案以使其更易于阅读。


  1. 应该由 PowerMockito 处理的类需要 在 @PrepareForTest 注释中声明。

  2. 如果注释用于创建模拟,则所有未在 @PrepareForTest 注释中声明的注释类都由 Mockito 创建。

  3. 如果注释用于创建模拟并调用 MockitoAnnotations.initMocks(this);, 这显然会导致声明被覆盖,所有模拟都由 Mockito 创建。 (来源:https://groups.google.com/forum/#!topic/powermock/yPBey4hr7IU)

  4. Mockito 无法处理静态或 final方法。
    模拟操作可能会静默失败。


问题的根源在于 HttpClientBuilder#setServiceUnavailableRetryStrategy 是一个 final 方法,因此不能由 Mockito 处理。

解决方案是 HttpClientBulder 的 Mock 必须由 PowerMockito 处理。 按照1.需要在@PrepareForTest注解中声明。

@PrepareForTest({ HttpClients.class, HttpClientBuilder.class, Sample.class})


如果您想使用注释来创建模拟,您不得调用

MockitoAnnotations.initMocks(this);

(参见 2./我用最新的 powermockito 版本 (1.7.4/2.0.2) 验证了这个问题)


否则您必须手动创建模拟。

HttpClientBuilder clientBuilderMock = PowerMockito.mock(HttpClientBuilder.class);

关于java - 如何使用 junit mockito 覆盖匿名类重写方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57166142/

相关文章:

java - MockMvc 无法使用参数 @DateValid 进行验证

mockito - 使用 Mockito 模拟来自部分模拟的连续响应的通用数量

java - 使用 JUnit assertEquals 的自定义异常消息?

java - postgresql - java - 当数据库中发生某些事情时唤醒应用程序

java - 使用多个接口(interface)的最佳方式是什么?

java - @Mock 注释不适用于对象映射器

android - Realm 单元测试

java - 线程 "main"java.lang.NoClassDefFoundError : com/ibm/mq/MQException 中的异常

java - 如何根据机器字节序运行测试?

java - 找不到类 : "md.leonis.ServiceMagi?Test"