【发布时间】:2017-09-27 21:23:04
【问题描述】:
寻找一些关于为什么期望返回 null 而不是请求的模拟的指导。有问题的模拟是一个未来,并且遵循与其他正确返回的模拟相同的模式。
为了向具有 powermock 和 easymock 经验的人提供所有信息,我已经包含了所有代码,包括被测代码和设置模拟和行为的测试代码。有问题的期望是
EasyMock.expect( mockAsyncClient.execute( EasyMock.isA( HttpGet.class ),
EasyMOck.isA( HttpClientContext.class ), isNull() ).andReturn( mockFuture )
它产生一个 null 而不是返回一个模拟的 Future。
任何想法都将不胜感激。
附言测试这个功能需要大量的模拟设置,我希望这不会妨碍评估问题。任何删除不必要的模拟基础设施的建议将不胜感激。
这是正在测试的代码
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
@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 );
}
【问题讨论】:
-
null 通常在期望不匹配时返回,这向我表明您的某些参数匹配器与您期望的不匹配。我建议将匹配器更改为 anyObject() 并查看是否有帮助,然后您可以调试哪些不是您期望的类型。此外,由于有很多嘲笑正在进行,您的其他一些期望可能不匹配并且返回空值,因此调试并查看哪些变量为空也会有所帮助。最后一个问题,connManager 从何而来?
-
感谢您的意见。 connManager 是由类在构造期间构建的真实类型。至于其他空值,我通过注释掉对未来的期望来验证一切都很好。所有期望都得到满足,包括在 try-with-resources 块中隐含的 stop() 调用。我会按照您的建议尝试 anyObject() 。我曾尝试使用 anyObject(
) 代替 isA(...) 但它具有相同的行为。还尝试返回 IAnswer(){} 但未调用 answer() 方法。顺便说一句,在非模拟集成测试期间,代码可以工作。 -
测试了 anyObject() 但行为是一样的。但是,为了使其编译,我必须将第一个 anyObject() 引用转换为 HttpGet,因此期望可以解决调用哪个重载方法。我有一种感觉,类型擦除可能导致 EasyMock 期望失败。以前从未见过这种行为,模拟重载函数并不是什么新鲜事。
-
EasyMock.expect( mockAsyncClient.execute( EasyMock.isA( HttpGet.class ), EasyMock.isA( HttpClientContext.class ), EasyMock.isA( FutureCallback.class ) ) ) .andReturn( mockFuture );结果: 抑制:java.lang.IllegalStateException:缺少前面方法调用的行为定义:CloseableHttpAsyncClient.execute(GET 127.0.0.1:80 HTTP/1.1, org.apache.http.client.protocol.HttpClientContext@63dda940, null) 用法是: 期望(a.foo()).andXXX()
-
验证 execute() 方法模拟匹配签名类型。 Powermock 错误?除了从 execute() 方法返回的空引用之外,该方法的预期测试也失败了:... 抑制:java.lang.IllegalStateException:缺少前面方法调用的行为定义:CloseableHttpAsyncClient.execute(GET 127.0.0.1:80 HTTP/1.1, org.apache.http.client.protocol.HttpClientContext@edb83f8, xxx.RestClientTest$HttpResponseCallbackHandler@69a373fd) 用法是:expect(a.foo()).andXXX()
标签: java unit-testing powermock easymock