Java 使用PowerMock模拟私有方法,但仍会调用底层方法

Java 使用PowerMock模拟私有方法,但仍会调用底层方法,java,junit,mockito,powermock,Java,Junit,Mockito,Powermock,我试图模拟一个正在进行JNDI调用的私有方法。当从单元测试调用该方法时,它抛出一个异常^。我想模拟这种方法进行测试。我使用了,当测试通过时,底层方法似乎仍然被调用。我在doTheGamble()方法中插入了System.err.println(),并将其打印到我的控制台 有趣的是,如果我注释掉第一个断言,测试就通过了( 那么,如何模拟私有方法,使其不被调用呢 import static org.hamcrest.core.Is.is; import static org.junit.Assert

我试图模拟一个正在进行JNDI调用的私有方法。当从单元测试调用该方法时,它抛出一个异常^。我想模拟这种方法进行测试。我使用了,当测试通过时,底层方法似乎仍然被调用。我在
doTheGamble()
方法中插入了
System.err.println()
,并将其打印到我的控制台

有趣的是,如果我注释掉第一个
断言
,测试就通过了(

那么,如何模拟私有方法,使其不被调用呢

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.support.membermodification.MemberMatcher.method;

import java.util.Random;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(CodeWithPrivateMethod.class)
public class PowerMock_Test {

    static boolean gambleCalled = false; 

    @Test(expected = RuntimeException.class)
    public void when_gambling_is_true_then_always_explode() throws Exception {
        CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod());

        when(spy, method(CodeWithPrivateMethod.class, "doTheGamble", String.class, int.class))
                .withArguments(anyString(), anyInt())
                .thenReturn(true);

/* 1 */ assertThat( PowerMock_Test.gambleCalled, is(false) );
        spy.meaningfulPublicApi();
/* 2 */ assertThat( PowerMock_Test.gambleCalled, is(false) );
    }
}


class CodeWithPrivateMethod {

    public void meaningfulPublicApi() {
        if (doTheGamble("Whatever", 1 << 3)) {
            throw new RuntimeException("boom");
        }
    }

    private boolean doTheGamble(String whatever, int binary) {
        Random random = new Random(System.nanoTime());
        boolean gamble = random.nextBoolean();

        System.err.println( "\n>>> GAMBLE CALLED <<<\n" );
        PowerMock_Test.gambleCalled = true;

        return gamble;
    }
}   
导入静态org.hamcrest.core.Is.Is;
导入静态org.junit.Assert.assertThat;
导入静态org.mockito.Matchers.anyInt;
导入静态org.mockito.Matchers.anyString;
导入静态org.powermock.api.mockito.PowerMockito.when;
导入静态org.powermock.api.support.membermodification.MemberMatcher.method;
导入java.util.Random;
导入org.junit.Test;
导入org.junit.runner.RunWith;
导入org.powermock.api.mockito.PowerMockito;
导入org.powermock.core.classloader.annotations.PrepareForTest;
导入org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(CodeWithPrivateMethod.class)
公共类PowerMock_测试{
静态布尔值=false;
@测试(预期=RuntimeException.class)
公共无效当赌博为真时,则总是抛出异常{
CodeWithPrivateMethod spy=PowerMockito.spy(新的CodeWithPrivateMethod());
当(间谍,方法(CodeWithPrivateMethod.class,“doTheGamble”,String.class,int.class))
.withArguments(anyString(),anyInt())
.然后返回(true);
/*1*/断言(PowerMock_Test.com调用为(false));
spy.meaningfulPublicApi();
/*2*/断言(PowerMock_Test.com调用为(false));
}
}
类CodeWithPrivateMethod{
public void意为PublicAPI(){

如果(doTheGamble)(“Whatever”,1当你使用
spy
构造一个模拟对象时,它是一个真正的半背对象。我的猜测是摆脱
spy
。在纯模拟对象上工作。

来自:

因此,要将此应用于您的代码,我认为它可能会变成:

@RunWith(PowerMockRunner.class)
@PrepareForTest(CodeWithPrivateMethod.class)
public class PowerMock_Test {
    @Test(expected = RuntimeException.class)
    public void when_gambling_is_true_then_always_explode() throws Exception {
        CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod());

        PowerMockito.doReturn(true).when(spy, "doTheGamble", anyString(), anyInt());


/* 1 */ PowerMockito.verifyPrivate(spy, times(0)).invoke("doTheGamble", anyString(), anyInt());            
        spy.meaningfulPublicApi();
/* 2 */ PowerMockito.verifyPrivate(spy, times(2)).invoke("doTheGamble", anyString(), anyInt());            
    }
}
我只是在这里的编辑器中编写了代码。实际上没有运行任何测试,在编写代码的过程中也没有出现任何bug。

ArtB

你确定你的代码不起作用(或者)我在这里遗漏了什么吗?我刚才用Mike建议的方法将你的方法预期替换为以下方法,效果很好:

PowerMockito.doReturn(true).when(spy, 
               method(CodeWithPrivateMethod.class, "doTheGamble", String.class, int.class))
                .withArguments(anyString(), anyInt());
我从来没有用过Powermockito,但以前用过很多Mockito

只是粘贴了在我的EclipseIDE中运行良好的完整代码。我只是改变了我在上一篇文章中所说的期望。祝你好运

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.support.membermodification.MemberMatcher.method;

import java.util.Random;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(CodeWithPrivateMethod.class)
public class PowerMock_Test {

    static boolean gambleCalled = false; 

    @Test(expected = RuntimeException.class)
    public void when_gambling_is_true_then_always_explode() throws Exception {
        CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod());

//        PowerMockito.doReturn(true).when(spy, "doTheGamble", anyString(), anyInt());

        PowerMockito.doReturn(true).when(spy, 
               method(CodeWithPrivateMethod.class, "doTheGamble", String.class, int.class))
                .withArguments(anyString(), anyInt());

        assertThat( PowerMock_Test.gambleCalled, is(false) );
        spy.meaningfulPublicApi();
        assertThat( PowerMock_Test.gambleCalled, is(false) );
    }
}


class CodeWithPrivateMethod {

    public void meaningfulPublicApi() {
        if (doTheGamble("Whatever", 1 << 3)) {
            throw new RuntimeException("boom");
        }
    }

    private boolean doTheGamble(String whatever, int binary) {
        Random random = new Random(System.nanoTime());
        boolean gamble = random.nextBoolean();

        System.err.println( "\n>>> GAMBLE CALLED <<<\n" );
        PowerMock_Test.gambleCalled = true;

        return gamble;
    }
}   
导入静态org.hamcrest.core.Is.Is;
导入静态org.junit.Assert.assertThat;
导入静态org.mockito.Matchers.anyInt;
导入静态org.mockito.Matchers.anyString;
导入静态org.powermock.api.support.membermodification.MemberMatcher.method;
导入java.util.Random;
导入org.junit.Test;
导入org.junit.runner.RunWith;
导入org.powermock.api.mockito.PowerMockito;
导入org.powermock.core.classloader.annotations.PrepareForTest;
导入org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(CodeWithPrivateMethod.class)
公共类PowerMock_测试{
静态布尔值=false;
@测试(预期=RuntimeException.class)
公共无效当赌博为真时,则总是抛出异常{
CodeWithPrivateMethod spy=PowerMockito.spy(新的CodeWithPrivateMethod());
//doReturn(true).when(间谍,“doTheGamble”,anyString(),anyInt());
PowerMockito.doReturn(真)。当(间谍,
方法(CodeWithPrivateMethod.class、“doTheGamble”、String.class、int.class))
.withArguments(anyString(),anyInt());
断言(PowerMock_Test.called,is(false));
spy.meaningfulPublicApi();
断言(PowerMock_Test.called,is(false));
}
}
类CodeWithPrivateMethod{
public void意为PublicAPI(){

如果(doTheGamble)(“无论什么”,1以上任何一项对我都不起作用,因为我的私人方法是无效的

设置如下:

public class MainClass {
    public void publicFunction () {
      this.privateFunction(Arg1.class arg1, Arg2.class arg2);
    }

    private void privateFunction(Arg1.class arg1, Arg2.class arg2){
       // who cares, I don't want any of this to go off
    }

}
唯一有效的是:

@Test
public void whocares() throws Exception {
   mainSpy = spy(mockedMainClassInstance);
   PowerMockito.doNothing().when(mainSpy, "privateFunction", mockedArg1, mockedArg2);
   mainSpy.publicFunction(mockedArg0, mockedArg1, mockedArg2);
   verifyPrivate(mainSpy).invoke("privateFunction", mockedArg1, mockedArg2);
}


这时私有函数中的代码停止触发

我正试图测试我正在监视的类的实现,所以这不是一个选项。@Mike你知道为什么
doReturn(true)。when(spy,“doTheGamble”,anyString(),anyInt());
工作但
doReturn(true)。when(spy,method)(CodeWithPrivateMethod.class,“doTheGamble”,String.class,int.class))。带参数(anyString(),anyInt())
导致了
IllegalArgumentException:参数类型不匹配
?后者似乎更符合示例的风格,至少是等效的,但不起作用。老实说,我不能,对不起。我对Mockito/PowerMock比较陌生……我从来没有尝试过用这种风格(
。with arguments(…)编写代码
)之前。我完全未经证实的猜测是,您正在尝试将
int
整数
匹配……我已经尝试过了。使用不同对象的参数,但它似乎不起作用……PowerMockito.doReturn(true)。当(间谍,“doTheGamble”、anyString()、anyInt());工作起来很有魅力!@Christian-你能指导一下吗。我们如何确保100%的代码覆盖率?是的,我肯定,一旦我开始工作,我会粘贴一些输出。我只是忘记了@PrepareForest
@Test
public void whocares() throws Exception {
   mainSpy = spy(mockedMainClassInstance);
   PowerMockito.doNothing().when(mainSpy, "privateFunction", mockedArg1, mockedArg2);
   mainSpy.publicFunction(mockedArg0, mockedArg1, mockedArg2);
   verifyPrivate(mainSpy).invoke("privateFunction", mockedArg1, mockedArg2);