java 如何存根 Mockito 测试的类的私有方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39189675/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 04:09:48  来源:igfitidea点击:

How to stub private methods of class under test by Mockito

javamockito

提问by Vanguard

Say we have java class called SomeClass

假设我们有一个名为 SomeClass 的 Java 类

public class SomeClass {

    private boolean isMethod() {

        return false;
    }

    public void sendRequest(String json, String text) {

        int messageId;

        if (isMethod()) {
            messageId = getMessageId(json);
            sendMessage(messageId, text);
        } else {
            throw new IllegalArgumentException();
        }
    }

    private void sendMessage(int messageId, String text) {

    }

    private int getMessageId(String text) {

        Pattern p = Pattern.compile("messageId=(\d+)&");
        Matcher m = p.matcher(text);

        if (m.find()) {
            return Integer.valueOf(m.group(1));
        }
        return 0;
    }
}

Don't pay attention to methods' name, they're all optional.

不要注意方法的名称,它们都是可选的。

  • I want to test sendRequest(String json, String text)method in isolation.
  • I want to stub methods isMethod()and getMessageId(json), and verify that sendMessage(messageId, text)method is called.
  • I need to be sure that getMessageId(json)returns 25 and that isMethod()returns true no matter which argument value given.
  • 我想单独测试sendRequest(String json, String text)方法。
  • 我想存根方法isMethod()getMessageId(json),并验证该sendMessage(messageId, text)方法被调用。
  • 我需要确保getMessageId(json)返回 25 并且isMethod()无论给出哪个参数值都返回 true。

回答by Vanguard

This could be achieved by PowerMockito framework.

这可以通过 PowerMockito 框架来实现。

import org.junit.Before;
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(SomeClass.class)
public class SomeClassTest {

    private SomeClass someInstance;

    @Before
    public void setUp() throws Exception {

        someInstance = PowerMockito.spy(new SomeClass());
    }

    @Test
    public void sendRequest() throws Exception {

        String json = "JSON";
        String text = "Some text";
        int messageId = 1;

        PowerMockito.doReturn(true).when(someInstance, "isMethod");
        PowerMockito.doReturn(messageId).when(someInstance, "getMessageId", json);

        someInstance.sendRequest(json, text);

        PowerMockito.verifyPrivate(someInstance).invoke("isMethod");
        PowerMockito.verifyPrivate(someInstance).invoke("getMessageId", json);
        PowerMockito.verifyPrivate(someInstance).invoke("sendMessage", messageId, text);
    }

}

回答by oldbam

In addition to what was said in this answer, I would add that the desire to test whether private method was called indicates that you are testing implementationas oppose to the public contract of a class. It is not an optimal idea, because it makes your refactoring more difficult. The idea of refactoring is that you can change inner workings of your code without violating it's contract. And your unit tests help you make sure that while changing the implementation, you did not introduce any changes to the contract.

除了此答案中所说的内容之外,我还要补充一点,测试是否调用了私有方法的愿望表明您正在测试implementationpublic contract of a class. 这不是一个最佳想法,因为它使您的重构更加困难。重构的想法是您可以在不违反合同的情况下更改代码的内部工作方式。和单元测试有助于确保在改变的implementation,你没有介绍到的任何变化contract

So, in your case a better option would be to restructure your code so that your test calls public methods and verifies the result based on return values

因此,在您的情况下,更好的选择是重构您的代码,以便您的测试调用公共方法并根据返回值验证结果

回答by Илья Косолапов

Vanguardgave right answer but who use Mavenneeds dependensies

先锋给出了正确的答案,但谁使用Maven需要依赖

<!-- https://mvnrepository.com/artifact/org.powermock/powermock-module-junit4 -->
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.0</version>
    <scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito2 -->
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.0</version>
    <scope>test</scope>
</dependency>