Mocking a static void methid with PowerMock & Mockito

7,460 views
Skip to first unread message

tsuna

unread,
Feb 24, 2010, 2:26:53 PM2/24/10
to powe...@googlegroups.com
Hi there,
I'm trying to stub out a call to Thread.sleep() to make my tests run
faster. I can't seem to get this right, even though I looked at the
tests that come with PowerMock and the archives on this mailing list.
Here's a sample code:

-------------------- StaticVoidThreadSleep.java --------------------
package omg;

public final class StaticVoidThreadSleep {

public void doSomething() throws InterruptedException {
Thread.sleep(30000);
}

}
------------------------------------------------------------------------------------------

And my test:
-------------------- TestStaticVoidThreadSleep.java --------------------
package omg;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.mockito.Mockito.*;

import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
public final class TestStaticVoidThreadSleep {

@PrepareForTest(Thread.class)
@Test
public void doSomethingQuick() throws Exception {
PowerMockito.mockStatic(Thread.class);
Thread.sleep(anyInt()); // Not sure whether that's the right way
to stub out the call...

StaticVoidThreadSleep t = new StaticVoidThreadSleep();
t.doSomething();
}

}
------------------------------------------------------------------------------------------

My test is still calling the real Thread.sleep():
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at omg.StaticVoidThreadSleep.doSomething(StaticVoidThreadSleep.java:6)
at omg.TestStaticVoidThreadSleep.doSomethingQuick(TestStaticVoidThreadSleep.java:22)

What am I doing wrong? Thanks.

--
Benoit "tsuna" Sigoure

tsuna

unread,
Feb 24, 2010, 4:26:05 PM2/24/10
to powe...@googlegroups.com
I forgot to mention that I'm using the following:
junit-4.5.jar
mockito-all-1.8.2.jar
powermock-mockito-1.3.5-full.jar
javassist.jar from javassist-3.11.GA.zip

Running on: java version "1.6.0_17"
Java(TM) SE Runtime Environment (build 1.6.0_17-b04-248-10M3025)
Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01-101, mixed mode)

s/methid/method/ in the subject :)

Thanks.

--
Benoit "tsuna" Sigoure
Software Engineer @ www.StumbleUpon.com

Johan Haleby

unread,
Feb 25, 2010, 11:50:08 AM2/25/10
to powe...@googlegroups.com
Hi,

Mocking methods in system classes requires special setup (because it's impossible to byte-code manipulate them), see documenation. So what you're looking for is something like:
@RunWith(PowerMockRunner.class)
@PrepareForTest(StaticVoidThreadSleep.class)
public final class TestStaticVoidThreadSleep {

 
 @Test
 public void doSomethingQuick() throws Exception {
        mockStatic(Thread.class);

        doNothing().when(Thread.class);
        Thread.sleep(anyLong());

        StaticVoidThreadSleep t = new StaticVoidThreadSleep();
       t.doSomething();
 }
}
 
I've uploaded an example to our subversion as well, see method "mockingStaticVoidMethodWorks".

/Johan


--
You received this message because you are subscribed to the Google Groups "PowerMock" group.
To post to this group, send email to powe...@googlegroups.com.
To unsubscribe from this group, send email to powermock+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/powermock?hl=en.


tsuna

unread,
Feb 25, 2010, 6:31:15 PM2/25/10
to powe...@googlegroups.com
On Thu, Feb 25, 2010 at 8:50 AM, Johan Haleby <johan....@gmail.com> wrote:
> Hi,
> Mocking methods in system classes requires special setup (because it's
> impossible to byte-code manipulate them), see documenation.
[...]

> I've uploaded an example to our subversion as well, see method
> "mockingStaticVoidMethodWorks".

OK, that's why I was confused as to why sometimes you need to use
@PrepareForTest(ClassInWhichTheresStaticMethod) and sometimes
@PrepareForTest(ClassBeingTested).

On http://code.google.com/p/powermock/wiki/MockSystem, point #2 says
that the @PrepareForTest annotation has to be used "at the class-level
of the test case". It also works at the method-level.

Would it possible to link the new MockSystem page from
http://code.google.com/p/powermock/wiki/MockitoUsage? It would make
it easier to find that page.

My test works now, thank you so much. PowerMock is awesome!

One minor nit: I noticed that there's a huge spike in CPU usage before
my tests start running. If I remove everything related to PowerMock,
it disappears. Are @PrepareForTest and such doing some expensive
stuff?

Johan Haleby

unread,
Feb 26, 2010, 2:16:48 AM2/26/10
to powe...@googlegroups.com
Hi,

I can see that it's confusing regarding which classes you need to prepare for test, that's probably the hardest part of using PowerMock until you've got your head around it. Basically it's always the class that contains that stuff that is not mockable the needs to be prepared, the exception is  Java system classes. Remember that for mocking "new" then the trick to remember is actually that you want to mock the construction of the new object, not the object itself. Thus you should prepare the class doing new! I.e. if B does "A a = new A()" you should prepare B.class and not A because we need to change the way B creates A.

http://code.google.com/p/powermock/wiki/MockitoUsage is for the old PowerMock+Mockito integration, you probably mean http://code.google.com/p/powermock/wiki/MockitoUsage13. I can add a hint on that page. 

Yes there's a lot of stuff going on when you use PrepareForTest and RunWith(PowerMockRunner.class), byte-code manipulation and classloading. I've tried to investigate what's causing so much time and I think it's the byte-code manipulation. There's an issue raised on this: http://code.google.com/p/powermock/issues/detail?id=196.

Glad that you got it working.

/Johan


Reply all
Reply to author
Forward
0 new messages