如何使用 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: 未捕获参数值! 你可能忘了在verify()中使用argument.capture() ...或者你在存根中使用了 capture(),但没有调用存根方法。 谁能帮我解决这个问题。我想测试重试请求方法功能。

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


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

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

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

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


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

解决方案是HttpClientBulder的模拟必须由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);

相关内容

  • 没有找到相关文章

最新更新