PowerMock Tutorial
Charles Roth, 10 April 2012
I. Introduction
PowerMock is an "add-on", of sorts, for EasyMock. It adds the ability to mock things that would not normally be considered possible, such as private methods, static methods, even constructors. It is a separate package from EasyMock, but it "plays well" with EasyMock and other mocking frameworks (e.g. Mockito). See the
javadoc for full details.
We use PowerMock in about 4% of the unit-test classes for our largest application. Some of the ways in which we've used PowerMock are now obsolete. For example, EasyMock 2 did not support "partial mocks" (mocking only a subset of methods for a class), so we had to use PowerMock. We're now using EasyMock 3, which does support partial mocks, so it's better to use the EasyMock 3 syntax.
While PowerMock is a very powerful tool, we should always remember one thing: if we find ourselves in a situation where only PowerMock can solve our problems with our own classes, then we have failed. I don't mean that the unit-test is wrong. I mean that the class under test is wrong.
For example, if we have to mock a static method, then the method shouldn't have been static in the first place. If you find yourself in this situation, take the time to consider moving the static method into a new class that can be instantiated or injected, and remove the "static". We'll all thank you for it. (Sometimes the static method is in a third-party class that we have no control over. That's really what PowerMock was invented for.)
(With very rare exceptions -- mostly the static classes like Math that provided with Java -- statics are evil. They tie your hands to a specific, concrete, implementation, yet we know that our most common business requirement is change. Don't be tempted!)
II. Mocking statics
All of the above being said, if you really do need PowerMock, the rest of this document will describe common ways to use PowerMock. Starting with the please-don't-ever-do-this-unless-you-really-have-to mock of a static method.
Here's an example: a method Dice.sumOfNumDieRolls that adds up dice rolls. To test that it is doing the summation properly, we have to "nail down" Math.random, a static method provided with java, so it always rolls a "3".
public class Dice {
public int sumOfNumDieRolls (int num) {
int sum = 0;
for (int i=0; i<num; ++i) {
int roll = (int) (6. * Math.random()) + 1;
sum += roll;
}
return sum;
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest( {Dice.class} )
public class DiceTest {
@Test
public void shouldAddUpDieRollsCorrectly() {
PowerMock.mockStaticPartial(Math.class, "random");
EasyMock.expect (Math.random()).andReturn(0.3334).anyTimes();
Dice die = new Dice();
PowerMock.replayAll();
assertEquals (12, die.sumOfNumDieRolls(4));
assertEquals (30, die.sumOfNumDieRolls(10));
PowerMock.verifyAll();
}
}
Notice that we're actually using EasyMock.expect() to define the expectation for Math.random. PowerMock messes with the bytecode for the Math class, and then lets EasyMock do the rest of the work.
Quiz for the reader: what's the "right" way to implement the Dice class, so that we don't have to mock a static in the first place? Hint: suppose we wanted to add up the rolls for "loaded" dice?
III. Mocking around permissions: final, private, protected
Mocking classes or methods that we're not allowed to get to, is another (mostly!) good reason to use PowerMock.
EasyMock simply can't mock a final class: it will complain "Cannot subclass final class". PowerMock, on the other hand, mucks about with the bytecodes, and lets you simply do:
SomeFinalClass xyz = PowerMock.createMock(SomeFinalClass.class);
and just create whatever expect() calls you want from there.
When your unit-test needs to mock private or protected methods in the class under test, it gets a little more complicated. Here's an example about climate change, that mocks a private method that (presumably) goes out to the 'net to a trusted source of weather data to get historic temperature. We can't have that in a test, of course, so we have to mock it.
public class Weather {
public String getTemperatureComparisonBetween (Date now, Date then) {
int temperatureDelta = temperature(now) - temperature(then);
if (temperatureDelta > 0) return "warmer than";
else if (temperatureDelta < 0) return "cooler than";
return "the same as";
}
private int temperature (Date date) {
...
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(Weather.class)
public class WeatherTest {
@Test
public void shouldDemonstrateGlobalWarming() throws Exception {
Date today = new Date("04/01/2012");
Date longAgo = new Date("04/01/1812");
Weather weather = PowerMock.createPartialMock(Weather.class, "temperature");
PowerMock.expectPrivate(weather, "temperature", today).andReturn(50);
PowerMock.expectPrivate(weather, "temperature", longAgo).andReturn(42);
PowerMock.replayAll();
String comparison = weather.getTemperatureComparisonBetween(today, longAgo);
PowerMock.verifyAll();
assertEquals ("warmer than", comparison);
}
}
Of course, this is a horrible design for the Weather class, and we should refactor it rather than suffer the PowerMocking. But if it's hugely complicated, or (better) if it's a third-party class we have no control over, then PowerMock it is.
If we're mocking a protected method, it may be better to simply make sure our unit-test is in the same package. Or if it's a private method, see if anything will really suffer from making it protected.
IV. Mocking Constructors
One of the biggest problems in writing unit-tests is the profligate use of "new" -- i.e, constructors. When the class you want to test in turn explicitly constructs its dependencies, you may have a big problem. (See my article on
"Tapestry IOC for Dummies" for an introduction to injecting dependencies instead of constructing them.)
Of course, a class that uses something simple (think "new StringBuilder()") is not a problem. But something that is going to talk to an outside service (think "new URL(...)") is a different story!
For the latter case, PowerMock provides a way to mock the actual constructor call -- which is both amazing, and dangerous. Amazing because it has to perform deep magic on the class in order to intercept the "new". Dangerous because it's almost too easy, when the right answer is remove the "new" and inject the dependency.
The code example this time is from some real code, and it demonstrates mocking both constructors and statics, and why PowerMock is especially useful in strange edge cases.
AutoReloadingProperties
I needed a Map of properties that could be automatically reloaded from a file, whenever the file changed, without restarting the application. That wasn't hard to write -- but it was hard to test, because of a nasty feature (bug?) in Java. Specifically, that File.lastModified() has a quantum time of 1 second on Linux. Essentially, that means that when I ask for the time a file was modified, the answer comes back in whole seconds (even though the value is actually a long number of milliseconds). To write a test for this, I'd have to write to the file system, wait at least 1 (and more likely 2) seconds, and then verify the result. That's just 'way too long for a unit-test.
So instead I mocked both "new File()" and (the static class) FileUtils. After all, I'm not testing Java file I/o (especially because it's partly broken in this edge case!), I'm testing my logic that uses the file system.
The key part of the AutoReloadingProperties class runs in a separate thread, gets the file name and sleep time from System properties, and keeps checking to see if the file has changed:
private class AutoReloader implements Runnable {
public void run() {
while (continueReloading) {
sleepQuietly(sleepTime);
if (fileHasChangedSince(propertiesFile, lastLoadTime))
loadMap();
}
}
}
private boolean fileHasChangedSince (File propertiesFile, long lastLoadTime) {
return propertiesFile != null
&& propertiesFile.exists()
&& propertiesFile.canRead()
&& propertiesFile.lastModified() > lastLoadTime;
}
The test looks something like this (not all code is shown):
@RunWith(PowerMockRunner.class)
@PrepareForTest({AutoReloadingPropertiesImpl.class, FileUtils.class})
public class AutoReloadingPropertiesTest {
@Test
public void shouldAutomaticallyReloadProperty_useBreadCrumbs_fromFileAfterDelay() throws Exception {
System.setProperty(PROPERTIES_FILE, tempPropertiesFile.getAbsolutePath());
System.setProperty(PROPERTIES_TIME, "10");
File mockFile = PowerMock.createMock(File.class);
PowerMock.expectNew(File.class, tempPropertiesFile.getAbsolutePath()).andReturn(mockFile);
EasyMock.expect(mockFile.exists() ).andReturn(true).anyTimes();
EasyMock.expect(mockFile.canRead()).andReturn(true).anyTimes();
long now = System.currentTimeMillis();
EasyMock.expect(mockFile.lastModified()).andReturn(now);
EasyMock.expect(mockFile.lastModified()).andReturn(now + 300L).atLeastOnce();
PowerMock.mockStaticPartial(FileUtils.class, "readLines");
EasyMock.expect(FileUtils.readLines(mockFile)).andReturn(listOf("UseBreadCrumbs = true"));
EasyMock.expect(FileUtils.readLines(mockFile)).andReturn(listOf("UseBreadCrumbs = false")).anyTimes();
PowerMock.replayAll();
properties = new AutoReloadingPropertiesImpl();
assertTrue (properties.isUsingBreadcrumbs());
properties.sleepQuietly (40L);
assertFalse (properties.isUsingBreadcrumbs());
PowerMock.verifyAll();
}
So we create a mock File object, tell PowerMock to intercept (via expectNew) the "new File(...)", and instead return the mock we just made. Then we script what the exists(), canRead(), and lastModified() calls should return. Note that the first lastModified() call returns one value, and the second and subsequent calls return a different value! Similarly, we mock the static FileUtils class to supply the desired "UseBreadCrumbs" property as if it came from the (changing) file, first set to true, and then on the second (etc.) time set to false.
V. Closing Thoughts
The examples above demonstrate PowerMocks' most important capabilities, but there's also plenty more that it can do, such as suppress a method or constructor entirely, or create complicated partial mocks.
In closing, there are three main reasons for understanding PowerMock:
- How to mock around difficult-to-test cases, especially involving third-party or otherwise problematic software.
- Help in fixing bad practices. For example, if a complicated dependency is constructed in a class, you may need to write a PowerMock test first, and then refactor the class to inject the dependency. (At which point you could also rewrite the test to use EasyMock or a "stub" class. Incremental improvement!)
- Understanding existing tests that use PowerMock -- and how to remove and replace the PowerMock parts if at all possible!
Do not rush out and begin using PowerMock because it's cool. It should be your weapon of last resort. Software is often compared to wizardry, and in one of the most famous wizard/fantasy novels of all time (yes, before Harry Potter), A Wizard of Earthsea, the protagonist's mentor says:
"...as a man's real power grows and his knowledge widens, ever the way he can follow grows narrower; until at last he chooses nothing, but does only and wholly what he must do..."