• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Power Mockito for private methods

 
Greenhorn
Posts: 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
Sheriff
Posts: 5555
326
IntelliJ IDE Python Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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.
 
reply
    Bookmark Topic Watch Topic
  • New Topic