Saturday, November 7, 2009

PowerMock - Mocking Static Methods

Déjà vu!

I feel a bit uneasy when writing unit test against codes that invoke "heavyweight" static methods. The static methods that I have seen are unusually full of testosterone, hairy and they do stuffs that are quite unimaginable such as reflection, acquiring network resources, class loading and ahem... Do we still need to go further?

As I sit here and start recalling the static methods I last looked at, indeed, life is BLEAK.

At times, I really wish that I could close my eyes and quietly sweep them under the carpet - "Look Ma, I don't have to worry about static methods anymore!"


Wishful thinking.

One way to get around this problem is to provide a helper class with non-static wrapper methods. I personally wouldn't want to go down this path as it adds an extra class and methods, not to mention complexity, to the codebase just to delegate calls to static methods without introducing any real benefit. Another way is to partial mock or...


PowerMock to the rescue!

After searching high and low for the best way to solve this by mocking, my friend Google suggested that I look at PowerMock.

To see PowerMock in action, let's write a sample class with static method:
SimonGarfunkel.java

1:  package test1;  
2: public class SimonGarfunkel {
3: public static void simonSaysGarfunkel() {
4: System.out.println("simon says garfunkel");
5: }
6: }


And the test class:
SimonGarfunkelTest.java

1:  package test1;
2: import org.junit.Test;
3: import org.junit.runner.RunWith;
4: import org.powermock.api.easymock.PowerMock;
5: import org.powermock.core.classloader.annotations.PrepareForTest;
6: import org.powermock.modules.junit4.PowerMockRunner;
7: @RunWith(PowerMockRunner.class)
8: @PrepareForTest(SimonGarfunkel.class)
9: public class SimonGarfunkelTest {
10: @Test
11: public void simonSaysGarfunkel() {
12: System.out.println("simonSaysGarfunkel");
13: SimonGarfunkel.simonSaysGarfunkel();
14: }
15: @Test
16: public void mockSimonSaysGarfunkel() {
17: System.out.println("mockSimonSaysGarfunkel");
18: PowerMock.mockStatic(SimonGarfunkel.class);
19: SimonGarfunkel.simonSaysGarfunkel();
20: PowerMock.expectLastCall().atLeastOnce();
21: PowerMock.replay(SimonGarfunkel.class);
22: SimonGarfunkel.simonSaysGarfunkel();
23: PowerMock.verify(SimonGarfunkel.class);
24: }
25: }


The code at line 20 and 23 ensures that "SimonGarfunkel.simonSaysGarfunkel()" is invoked at least once.

Also include the following dependencies into the pom file:
pom.xml

   <repositories> 
<repository>
<id>powermock-repo</id>
<url>http://powermock.googlecode.com/svn/repo/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-release-full</artifactId>
<version>1.3.1</version>
<scope>test</scope>
</dependency>
</dependencies>


For some reason, Maven2 didn't quite resolve powermock artifact even after I added the powermock repository. I had to manually download and install this into my local repo.