问题
Say we have java class called SomeClass
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.
回答1:
This could be achieved by PowerMockito framework.
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);
}
}
回答2:
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
.
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
回答3:
Vanguard gave right answer but who use Maven needs dependensies
<!-- 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>
来源:https://stackoverflow.com/questions/39189675/how-to-stub-private-methods-of-class-under-test-by-mockito