简体   繁体   English

Mockito doReturn /何时执行实数方法(不使用CGILIB)

[英]Mockito doReturn/when executes real method (without CGILIB)

I have done many Mockito spy and just imitating my own working examples in a new project. 我做了很多Mockito间谍,并且只是在一个新项目中模仿了自己的工作示例。 But this failed miserably 但这不幸地失败了

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static org.mockito.Mockito.*;

public class SpyTest {
    HttpClient httpClient;
    private HttpResponse httpResponse;
    private StatusLine responseStatus;
    private HttpEntity responseEntity;

    @BeforeMethod
    public void setupClient() throws Exception {
        List spy = spy(new ArrayList());
        doReturn(true).when(spy).addAll(any(Collection.class)); // this works!

        DefaultHttpClient directClient = new DefaultHttpClient();
        httpClient = spy(directClient);
        httpResponse = mock(HttpResponse.class);
        responseStatus = mock(StatusLine.class);
        responseEntity = mock(HttpEntity.class);
        doReturn(responseStatus).when(httpResponse).getStatusLine();
        doReturn(responseEntity).when(httpResponse).getEntity();
        doReturn(httpResponse).when(httpClient).execute(any(HttpPost.class)); // failing here
    }

    @Test
    public void itShouldSetupTheSpy() throws Exception {
        doReturn(200).when(responseStatus).getStatusCode();
        doReturn("OK").when(responseStatus).getReasonPhrase();
        doAnswer(new Answer() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                OutputStream os = (OutputStream) invocation.getArguments()[0];
                os.write("{\"id\": 100}".getBytes());
                return null;
            }
        }).when(responseEntity).writeTo(any(OutputStream.class));
    }
}

But I got error 但是我有错误

java.lang.IllegalArgumentException: Request must not be null.
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:801)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:784)
    at SpyTest.setupClient(SpyTest.java:37)

I believe I have followed the official advice ! 相信我已经听从了官方的建议 closely, like my other spies. 像其他间谍一样紧密 And this answer ! 这个答案 does not seem to apply to me since I don't use CGLIB as evident from the maven dependency tree: 似乎不适用于我,因为我没有使用CGLIB,这从maven依赖树可以明显看出:

[INFO] +- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.3:compile
    [INFO] |  \- org.codehaus.jackson:jackson-core-asl:jar:1.9.3:compile
    [INFO] +- org.testng:testng:jar:6.8:test
    [INFO] |  +- junit:junit:jar:4.10:test
    [INFO] |  |  \- org.hamcrest:hamcrest-core:jar:1.1:test
    [INFO] |  +- org.beanshell:bsh:jar:2.0b4:test
    [INFO] |  +- com.beust:jcommander:jar:1.27:test
    [INFO] |  \- org.yaml:snakeyaml:jar:1.6:test
    [INFO] +- org.mockito:mockito-all:jar:1.9.5:test
    [INFO] +- com.newrelic:newrelic-api:jar:2.3.0:compile
    [INFO] +- org.apache.httpcomponents:httpclient:jar:4.2.5:compile
    [INFO] |  +- org.apache.httpcomponents:httpcore:jar:4.2.4:compile
    [INFO] |  +- commons-logging:commons-logging:jar:1.1.1:compile
    [INFO] |  \- commons-codec:commons-codec:jar:1.6:compile
    [INFO] \- org.apache.commons:commons-lang3:jar:3.1:compile

It looks like having problem with the HttpClient and its subclasses. 看起来HttpClient及其子类有问题。

execute is a final method , and Mockito can't mock final methods (as mentioned in the section on spying and also the FAQ ). execute最终方法 ,而Mockito无法模拟最终方法(如有关间谍的部分以及FAQ所述 )。

Why? 为什么? Because you can't override final methods under normal circumstances, Java takes a shortcut and compiles calls (to final methods) directly to the implementations instead of looking them up in Java's equivalent of a virtual method table . 由于在正常情况下您无法覆盖最终方法,因此Java采用快捷方式并将调用(对最终方法)直接编译为实现,而不是在Java的等效虚拟方法表中查找它们。 This means that Mockito is never involved in final method calls, and therefore can't intercept behavior or even receive stubbing/verification calls. 这意味着Mockito永远不会参与最终方法调用,因此无法拦截行为,甚至无法接收存根/验证调用。

Can you switch to mocking and using a raw HttpClient instead? 您可以切换到模拟并使用原始的HttpClient吗? You can mock any method of an interface without worrying about visibility or final method problems. 您可以模拟接口的任何方法,而不必担心可见性或最终方法问题。

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

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