简体   繁体   English

PowerMock与EasyMock,期望返回null而不是模拟

[英]PowerMock with EasyMock, expectation returns null instead of a mock

Looking for some guidance as to why an expectation returns null instead of the requested mock. 寻找有关为何期望返回null而不是请求的模拟的指导。 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. 为了向具有powermock和easymock经验的人提供所有信息,我提供了所有代码,包括受测代码和设置模拟和行为的测试代码。 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. 它产生一个null而不是返回一个模拟的Future。

Any ideas would be appreciated. 任何想法,将不胜感激。

ps there is an awful lot of mock setup required to test this function, which I hope doesn't hinder evaluating the problem. ps有很多模拟安装程序需要测试此功能,我希望这不会妨碍评估问题。 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 );
}

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: 我错误地使用EasyMock而不是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拥有用于创建的模拟,并且只能验证这些模拟的行为。 PowerMock wraps EasyMock and so needs visibility into the mocks under control. PowerMock包装了EasyMock,因此需要对受控对象进行可视化。

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. 谢谢,罗宾。

I wound up here because I was trying to whenNew(SomeClass.class).withAnyArguments() on a class like: 我在这里总结,因为我试图在类似这样的类上使用whenNew(SomeClass.class).withAnyArguments()

class SomeClass {
     public SomeClass(String... args) { }
}

Turns out that withAnyArguments() doesn't match varargs. 原来withAnyArguments()与varargs不匹配。 In my case the fix was: 就我而言,解决方法是:

whenNew(SomeClass.class).withArguments(Matchers.<String>anyVararg()).thenReturn(myMock);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM