Reputation: 750
Looking for some guidance as to why an expectation returns null instead of the requested mock. The mock in question is a Future and is following the same pattern as other mocks that get returned correctly.
To provide all the information to someone with experience with powermock and easymock, I've included all the code, both code under test and the test code that sets up the mocks and behaviours. The expectation in question is
EasyMock.expect( mockAsyncClient.execute( EasyMock.isA( HttpGet.class ),
EasyMOck.isA( HttpClientContext.class ), isNull() ).andReturn( mockFuture )
which produces a null instead of returning a mocked Future.
Any ideas would be appreciated.
p.s. there is an awful lot of mock setup required to test this function, which I hope doesn't hinder evaluating the problem. Any advice to remove unnecessary mocking infrastructure would be appreciated.
Here's the code under test
public <T> T getResponse( ResponseHandler<T> responseHandler )
throws IOException, InterruptedException, ExecutionException
{
String connectTo = buildUri();
try( CloseableHttpAsyncClient httpClient =
HttpAsyncClients.custom()
.setConnectionManager( connManager )
.build() ) {
HttpGet request = new HttpGet( connectTo );
HttpClientContext ctx = HttpClientContext.create();
addHeaders( request );
httpClient.start();
Future<HttpResponse> futureResponse = httpClient.execute( request, ctx, null ); //<-- this line executes using a verified HttpClient mock but returns null
HttpResponse response = futureResponse.get();
return responseHandler.handleResponse( response );
}
}
test code:
@Test
@PrepareOnlyThisForTest( { HttpAsyncClients.class, HttpAsyncClientBuilder.class } )
public void testGetResponseCallsResponseHandler()
throws IOException, InterruptedException, ExecutionException
{
// create mocks to be used when exercising the code under test
CloseableHttpAsyncClient mockAsyncClient =
EasyMock.createMock( CloseableHttpAsyncClient.class );
PowerMock.mockStatic( HttpAsyncClients.class );
HttpAsyncClientBuilder mockClientBuilder =
PowerMock.createMock( HttpAsyncClientBuilder.class );
HttpAsyncClientBuilder mockClientBuilder2 =
PowerMock.createMock( HttpAsyncClientBuilder.class );
HttpResponse mockResponse = PowerMock.createMock( HttpResponse.class );
StatusLine mockStatusLine = PowerMock.createMock( StatusLine.class );
@SuppressWarnings( "unchecked" )
Future<HttpResponse> mockFuture = PowerMock.createMock( Future.class );
// set up expectations that use the mocks
EasyMock.expect( HttpAsyncClients.custom() ).andReturn( mockClientBuilder );
EasyMock.expect( mockClientBuilder.setConnectionManager( EasyMock.isA( NHttpClientConnectionManager.class ) ) )
.andReturn( mockClientBuilder2 );
EasyMock.expect( mockClientBuilder2.build() ).andReturn( mockAsyncClient );
mockAsyncClient.start();
EasyMock.expectLastCall().once();
EasyMock.expect( mockAsyncClient.execute( EasyMock.isA( HttpGet.class ),
EasyMock.isA( HttpClientContext.class ),
EasyMock.isNull() ) )
.andReturn( mockFuture );
EasyMock.expect( mockFuture.get() ).andReturn( mockResponse );
EasyMock.expect( mockResponse.getStatusLine() ).andReturn( mockStatusLine );
EasyMock.expect( mockStatusLine.getStatusCode() ).andReturn( 200 );
mockAsyncClient.close();
EasyMock.expectLastCall().once();
PowerMock.replayAll();
ClientConfig cfg = new ClientConfigBuilder().build();
RestClient client = new RestClient( cfg );
int statusCode = client.getResponse( new ResponseHandler<Integer>() {
@Override
public Integer handleResponse( HttpResponse response )
throws ClientProtocolException, IOException
{
StatusLine statusLine = response.getStatusLine();
return statusLine.getStatusCode();
}
} );
PowerMock.verifyAll();
assertEquals( "status code incorrect", 200, statusCode );
}
Upvotes: 1
Views: 1679
Reputation: 9131
I wound up here because I was trying to whenNew(SomeClass.class).withAnyArguments()
on a class like:
class SomeClass {
public SomeClass(String... args) { }
}
Turns out that withAnyArguments()
doesn't match varargs. In my case the fix was:
whenNew(SomeClass.class).withArguments(Matchers.<String>anyVararg()).thenReturn(myMock);
Upvotes: 0
Reputation: 750
I found the problem and it's one of those problems I'm sure has hit many others...
The mock that was returning a null can be explained by the fact I mistakenly used EasyMock to create the mock and not PowerMock:
CloseableHttpAsyncClient mockAsyncClient =
EasyMock.createMock( CloseableHttpAsyncClient.class );
By changing that line to
CloseableHttpAsyncClient mockAsyncClient =
PowerMock.createMock( CloseableHttpAsyncClient.class );
the test passed.
Reason is that PowerMock owns the mocks it is used to create and can only verify behaviour on those mocks. PowerMock wraps EasyMock and so needs visibility into the mocks under control.
For those affected by this problem, please upvote the question. Not sure why I was down-voted but please make this answer easier to discover.
Thanks, Robin.
Upvotes: 1