I have below code to retry the request based on response code.
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();
}
}
While I am writing the unit tests for this getInstance
method the overridden methods (retryRequest, getRetryInterval)
are not getting covered. How can I write the unit tests to get coverage for these methods as well. By googling I found we can use ArgumentCaptor
. I have tried the below code, but it does not work.
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()
is always giving me null
.I am getting like
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.
Edit: rephrased the answer to make it easier to read.
Classes that are supposed to be handeled by PowerMockito need to be declared in the
@PrepareForTest
annotation.If annotations are used to create the mocks all annotated classes which are not declared in the
@PrepareForTest
annotation, are created by Mockito.If annotations are used to create the mocks and
MockitoAnnotations.initMocks(this);
is called, this apparently causes the declaration to be overriden and all mocks are created by Mockito instead. (Source: https://groups.google.com/forum/#!topic/powermock/yPBey4hr7IU)Mockito can not handle static or final methods.
The mocking operation might fail silently.
The root of your problem is that HttpClientBuilder#setServiceUnavailableRetryStrategy
is a final method and therefore can not be handeled by Mockito.
The solution is that the Mock of HttpClientBulder
has to be handeled by PowerMockito. In accordance with 1.
it needs to be declared in the @PrepareForTest
annotation.
@PrepareForTest({ HttpClients.class, HttpClientBuilder.class, Sample.class})
If you want to use Annotations to create the mocks, you must not call
MockitoAnnotations.initMocks(this);
(see 2.
/ I verified this issue with the latest powermockito versions (1.7.4 / 2.0.2))
Else you have to create the mock manually.
HttpClientBuilder clientBuilderMock = PowerMockito.mock(HttpClientBuilder.class);