【问题标题】:How to mock private method of another Class other than the Class under test using PowerMock?如何使用 PowerMock 模拟除被测类以外的另一个类的私有方法?
【发布时间】:2016-05-28 19:19:47
【问题描述】:

我有一个类,我想用一个调用另一个类的私有方法的公共方法来测试它。当我尝试调用同一类的私有方法时,一切正常。当我尝试模拟从被测类调用的另一个私有方法时,就会出现问题。以下是测试类的代码示例。

@RunWith(PowerMockRunner.class)
@PrepareForTest({CodeWithPrivateMethod.class,CodeWithAnotherPrivateMethod.class})
public class CodeWithPrivateMethodTest {

    @Test
    public void when_gambling_is_true_then_always_explode() throws Exception {
        CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod());
        CodeWithAnotherPrivateMethod codeWithAnotherPrivateMethod = PowerMockito.spy(new CodeWithAnotherPrivateMethod());      

        /*when(codeWithAnotherPrivateMethod, method(CodeWithAnotherPrivateMethod.class, "doTheGame", String.class))
                .withArguments(anyString())
                .thenReturn(true);*/

        PowerMockito.when(codeWithAnotherPrivateMethod, "doTheGame", anyString()).thenReturn(true);
        //PowerMockito.doReturn(true).when(codeWithAnotherPrivateMethod, "doTheGamble", anyString(),anyInt());

        spy.meaningfulPublicApi();
    }
}

以下是被测类的代码示例

import java.util.Random;

public class CodeWithPrivateMethod {

    CodeWithAnotherPrivateMethod anotherPrivateMethod = new CodeWithAnotherPrivateMethod();

    public void meaningfulPublicApi() {
        if (anotherPrivateMethod.doTheGame("Whatever")) {
            System.out.println("kaboom");
        }
    } 
}

以下是从被测类调用的类的代码示例

import java.util.Random;

public class CodeWithAnotherPrivateMethod {

    public boolean doTheGame(String string) {
        return doTheGamble("Whatever", 1 << 3);
    }

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

所以我的问题是我如何成功地模拟 CodeWithAnotherPrivateMethod 类的 doTheGamble() 方法以使其始终返回 true?

【问题讨论】:

  • 如果您删除 cmets,可能会更容易阅读。我认为,一旦您创建了一个被测类的实例(CodeWithPrivateMethod)并创建了一个模拟本身(CodeWithAnotherPrivateMethod),您只需将被测类中的私有实例设置为模拟对象(检查Whitebox 提供帮助)。

标签: java unit-testing testing mockito powermock


【解决方案1】:

这里的问题是,尽管您在测试中创建了 CodeWithAnotherPrivateMethod 的间谍,但在 CodeWithPrivateMethod 中创建了 CodeWithAnotherPrivateMethod 的新实例。所以,实际上你并没有使用你的模拟。

CodeWithAnotherPrivateMethod anotherPrivateMethod = new CodeWithAnotherPrivateMethod();

为避免这种情况,您可以在创建新实例时强制返回 CodeWithAnotherPrivateMethod 模拟。您可以使用 PowerMockito whenNew() 功能来执行此操作。

例子:

PowerMockito.whenNew(CodeWithAnotherPrivateMethod.class).withAnyArguments().thenReturn(codeWithAnotherPrivateMethod);

最后,你的测试应该是这样的:

@Test
public void when_gambling_is_true_then_always_explode() throws Exception {
  // Spy CodeWithAnotherPrivateMethod and force return true when doTheGamble is called
  CodeWithAnotherPrivateMethod codeWithAnotherPrivateMethod = PowerMockito.spy(new CodeWithAnotherPrivateMethod());
  PowerMockito.doReturn(true).when(codeWithAnotherPrivateMethod, "doTheGamble", Mockito.anyString(), Mockito.anyInt());
  // Return your mock when a new instance of CodeWithAnotherPrivateMethod is created.
  PowerMockito.whenNew(CodeWithAnotherPrivateMethod.class).withAnyArguments().thenReturn(codeWithAnotherPrivateMethod);

  CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod());
  spy.meaningfulPublicApi();
}

希望对你有帮助。

【讨论】:

  • 谢谢,这就像一个魅力。但看起来我仍然对嘲笑感到困惑。还有一个简单的问题,每当我在监视 CodeWithAnotherPrivateMethod 类之前监视 CodeWithPrivateMethod 类时,结果并不像预期的那样。为什么会发生这种情况,请您解释一下?
  • 很高兴帮助 :) 那是因为当你窥探 CodeWithPrivateMethod 时,会创建一个新实例,所以此时,也创建了 CodeWithAnotherPrivateMethod 的新实例(并且这仍然没有被模拟,所以该实例是一个“真正的” CodeWithAnotherPrivateMethod 对象)。
  • 还不错 :) 看来我还有很长的路要走 :D
猜你喜欢
  • 2014-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
相关资源
最近更新 更多