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
How to stub private methods of class under test by Mockito
提问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()
andgetMessageId(json)
, and verify thatsendMessage(messageId, text)
method is called. - I need to be sure that
getMessageId(json)
returns 25 and thatisMethod()
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 implementation
as 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
.
除了此答案中所说的内容之外,我还要补充一点,测试是否调用了私有方法的愿望表明您正在测试implementation
与public 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>