I have a class which I would like to test with a public method that calls private one. I'd like to assume that private method works correctly. For example, I'd like something like doReturn....when...
. I found that there is possible solution using PowerMock, but this solution doesn't work for me.
How It can be done? Did anybody have this problem?

- 18,541
- 27
- 119
- 168

- 877
- 1
- 9
- 10
-
Another option is to make private method protected and add override for it in your test case. – SirVaulterScoff Oct 18 '11 at 07:53
-
Generally if you need to stub a private method you have a problem with your object model - have you considered a refactoring? – Emma Nov 08 '11 at 21:07
-
1@Emma Why? What if his method calls some external resource, like a db, and he want's to mock it out to inject some fake result? – grinch Mar 11 '13 at 18:01
-
@grinch He schould extract the code for accessing the external resource in a separate adapter class. This way he can easily mock the adapter class and separates the (business) logic in the tested class from technical details od accessing the external resource. – DAN Aug 04 '15 at 11:57
6 Answers
I don't see a problem here. With the following code using the Mockito API, I managed to do just that :
public 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();
return gamble;
}
}
And here's the JUnit test :
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;
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;
@RunWith(PowerMockRunner.class)
@PrepareForTest(CodeWithPrivateMethod.class)
public class CodeWithPrivateMethodTest {
@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);
spy.meaningfulPublicApi();
}
}

- 40,072
- 9
- 91
- 111
-
3Thank you for this answer, the sample code on their wiki only shows the API for working with an EasyMock backend, and not with Mockito. – Sled Nov 08 '11 at 20:45
-
9Note to other developers who have Hamcrest matcher classes in their IDE content assist favorites: they won't work for Mockito's .withArguments() method - you must use the Mockito matchers! ;) Took me a while to figure out why exceptions kept being thrown by my test code. – bcody Apr 02 '14 at 14:42
-
@Brice But how do you manage the Exception from the "when(spy, method(....." ? Is it good to have the test throw exception or use try catch ? – Gobliins Jan 23 '15 at 12:14
-
The `RuntimeException` and the `@Expected(...)` are just par of the example. Over the last years in JUnit I have found that `try catch` is the currently best thing to test exceptional behaviors, at least up Java 7 (see [answer](http://stackoverflow.com/questions/17426313/how-to-verify-that-an-exception-was-not-thrown/17428439#17428439)). As it may be possible to improve on that with Java 8 lambdas. – bric3 Jan 23 '15 at 14:47
-
1This did not work for me, however this answer from a different question did: https://stackoverflow.com/a/41519820/3860594 – john Feb 02 '21 at 20:56
-
@hey_you _this doesn't work with just any version of the powermockito library!_ Obviously this code worked for a long time. But you're right 10 years ago I should have given the JDK (likely Java 7) and the Powermock artifact coordinates (probably v1.[3-4]). Would this have solved your problem? It's unlikely as the JDK evolved significantly since and the libraries too, and running the old powermock a new JDK is likely to fail. – bric3 Dec 02 '21 at 08:32
-
@Brice it's a really annoying problem with answers on stackoverflow than posters don't specify the library or the imports they're using. – pavel_orekhov Dec 02 '21 at 08:59
-
-
note that ```@PrepareForTest(CodeWithPrivateMethod.class)``` is necessary – byhuang1998 Jan 31 '23 at 11:28
A generic solution that will work with any testing framework (if your class is non-final
) is to manually create your own mock.
- Change your private method to protected.
- In your test class extend the class
- override the previously-private method to return whatever constant you want
This doesn't use any framework so its not as elegant but it will always work: even without PowerMock. Alternatively, you can use Mockito to do steps #2 & #3 for you, if you've done step #1 already.
To mock a private method directly, you'll need to use PowerMock as shown in the other answer.
-
1
-
@ArtB If the private method is changed to protected there is no more need to create your own mock, since protected is also available into the whole package. (And test sohuld belongs to the same package as the class to test). – Anthony Raymond Apr 27 '16 at 14:22
-
@AnthonyRaymond but what if that method is doing something you don't want to be doing in a test? For example, I had some legacy code that was opening a hardcoded local file that was expected to exist in production but not in dev; causing it it die if done in dev. I used this technique to skip the reading of that file. – Sled Apr 27 '16 at 14:36
-
@ArtB I agree, but the question was "how to mock a private method" that means the class is going to be a mock. so if the method is visibility package, you can mock the method according to what you expect. IMO extending the class instead of mocking is smashing a fly with a hammer. – Anthony Raymond Apr 27 '16 at 15:17
-
Thanks, I tried multiple solutions, this is so simple, it's brilliant. Shame on me not thinking the same thing right away. – 98percentmonkey Sep 22 '16 at 09:09
-
it's a working approach, but it's a bad decision to change your code for the sake of tests – Andrew Jul 18 '21 at 14:52
For some reason Brice's answer is not working for me. I was able to manipulate it a bit to get it to work. It might just be because I have a newer version of PowerMock. I'm using 1.6.5.
import java.util.Random;
public 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();
return gamble;
}
}
The test class looks as follows:
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;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.doReturn;
@RunWith(PowerMockRunner.class)
@PrepareForTest(CodeWithPrivateMethod.class)
public class CodeWithPrivateMethodTest {
private CodeWithPrivateMethod classToTest;
@Test(expected = RuntimeException.class)
public void when_gambling_is_true_then_always_explode() throws Exception {
classToTest = PowerMockito.spy(classToTest);
doReturn(true).when(classToTest, "doTheGamble", anyString(), anyInt());
classToTest.meaningfulPublicApi();
}
}

- 1,177
- 14
- 15
-
It might sound obvious, but I had trouble with org.mockito.Mockito.doReturn being imported instead of org.powermock.api.mockito.PowerMockito.doReturn. Once i used the right import the above by @gaoagong worked a treat for me – t0mmyw May 02 '18 at 13:35
i know a way ny which you can call you private function to test in mockito
@Test
public void commandEndHandlerTest() throws Exception
{
Method retryClientDetail_privateMethod =yourclass.class.getDeclaredMethod("Your_function_name",null);
retryClientDetail_privateMethod.setAccessible(true);
retryClientDetail_privateMethod.invoke(yourclass.class, null);
}

- 203
- 3
- 9
-
The questioner is assuming that the private method is implemented correctly, not actually implementing it – byhuang1998 Jan 31 '23 at 09:15
With no argument:
ourObject = PowerMockito.spy(new OurClass());
when(ourObject , "ourPrivateMethodName").thenReturn("mocked result");
With String
argument:
ourObject = PowerMockito.spy(new OurClass());
when(ourObject, method(OurClass.class, "ourPrivateMethodName", String.class))
.withArguments(anyString()).thenReturn("mocked result");
-
```method(OurClass.class, "ourPrivateMethodName", String.class))``` which package is method in? – byhuang1998 Jan 31 '23 at 09:10
Something to Consider
Make sure the private function is calling another public function and you can proceed only mocking the public function.

- 1,621
- 19
- 20