aspose file tools*
The moose likes Testing and the fly likes Power Mockito for private methods Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of The Java EE 7 Tutorial Volume 1 or Volume 2 this week in the Java EE forum
or jQuery UI in Action in the JavaScript forum!
JavaRanch » Java Forums » Engineering » Testing
Bookmark "Power Mockito for private methods" Watch "Power Mockito for private methods" New topic
Author

Power Mockito for private methods

S Khandelwal
Greenhorn

Joined: Sep 08, 2013
Posts: 1
I have written a code that mocks private method using Power Mockito.

Source class :This is the class that needs to be tested.
The Private Method is doTheGamble

package com.kronos.wfc.platform.messaging.framework;

import java.util.Random;

public class Abc{

public void meaningfulPublicApi() {
if (doTheGamble()) {
throw new RuntimeException("boom");
}
}

private boolean doTheGamble() {
Random random = new Random(System.nanoTime());
boolean gamble = random.nextBoolean();
return gamble;
}
}

The Test I wrote is

package com.kronos.wfc.platform.messaging.framework;



//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;
import junit.framework.TestCase;

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(Abc.class)
public class AbcMicrotest extends TestCase {

protected void setUp() throws Exception {
super.setUp();
PowerMockito.mockStatic(Abc.class);
}

protected void tearDown() throws Exception {
super.tearDown();
}
public void testmeaningfultest1()
{
Abc spy = PowerMockito.spy(new Abc());
try{
PowerMockito.doReturn(true).when(spy, "doTheGamble");


spy.meaningfulPublicApi();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}


}

Errors :

org.mockito.exceptions.base.MockitoException:
'meaningfulPublicApi' is a *void method* and it *cannot* be stubbed with a *return value*!
Voids are usually stubbed with Throwables:
doThrow(exception).when(mock).someVoidMethod();
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. The method you are trying to stub is *overloaded*. Make sure you are calling the right overloaded version.
2. Somewhere in your test you are stubbing *final methods*. Sorry, Mockito does not verify/stub final methods.
3. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.

at com.kronos.wfc.platform.messaging.framework.AbcMicrotest.testmeaningfultest1(AbcMicrotest.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:131)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

What version of the product are you using? On what operating system?
I am working on Eclipse IDE

Please help me with this.
Thanks in advance
Tim Cooke
Bartender

Joined: Mar 28, 2008
Posts: 954
    
  47

Hi there,

I get from your post that you are intending to stub out the private method doTheGamble() so that you can make it always return true for your test.

Might I suggest an alternative simpler approach that does not require the use of PowerMock. The part of the code that is troublesome for testing is the dependency on the Random object because we have no control over its behaviour. So for testing purposes this is the thing that we want to replace with our own Test Double. The way to do this is to wrap the java.util.Random class in our own domain construct and then use Dependency Injection. Here is how I might write the production code:

(We don't really even need the private method here at all, I could have just inlined the randomBoolean.generate() into the if predicate, but I've left it in to mirror the structure of your original Abc class)

There are advantages to this approach:
1) We have decoupled the java.util.Random library from our Gambler class which is good because we should always strive to write loosely coupled code. If we decide in the future that the java.util.Random library is just not doing it for us anymore we can write some other implementation of RandomBoolean and drop it in without having to alter the Gambler class.
2) We have encapsulated the task of generating random boolean values into its own class, thus simplifying the Gambler class. Remember, a function should do one thing only.
3) By having the Gambler class dependent on an interface, we can easily replace that dependency in our tests with a Test Double.

For this code I might write the following tests:

I've used inner classes here for convenience of demonstrating my approach but if you had other tests that are dealing with RandomBoolean's then you could just as well implement them as public classes in your test package so they can be reused.

For this test I have used nothing but jUnit. No need for elaborate mocking frameworks such as PowerMock.


Tim Driven Development
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Power Mockito for private methods