Wednesday, April 28, 2010

PowerMock - Mocking Statics - Supplemental Documentation

I have recently suffered through a bit of pain working with PowerMock.  It seemed extremely promising, as it sits on top of EasyMock, which we use for mock objects in our unit tests (it also works with Mockito, apparently), and promises to give you the tools to mock those pesky static calls that kill testability.  I had a few issues getting started, and they centered around jUnit 3.

PowerMock with jUnit 3

All the examples and documentation seem to be based on jUnit 4. This page has great examples on how to run your static mocking tests when running on jUnit 4, but how to do it on jUnit 3??  An extremely simple example of how to do this in jUnit 4 is here:


@RunWith(PowerMockRunner.class)
public class AwesomeTest {

  @PrepareForTest(StaticClass.class)
  public void testDoExecute() throws Exception {
    ...
    PowerMock.mockStatic(StaticClass.class);

    expect( StaticClass.doStuff( param ) ).andReturn( "yo!" );
    replay( StaticClass.class );

    //test some stuff!
  }
}


To accomplish the same thing in jUnit 3, without the annotation support, you can do this:



public class MyPowerMockSuite extends PowerMockSuite {

  public static TestSuite suite() throws Exception {
  
    return new PowerMockSuite(AwesomeTest.class);
  }
 
  public static void main(String[] args) throws Exception {
  
    junit.textui.TestRunner.run( suite() );
  }  
}

public class AwesomeTest {

  @PrepareForTest(StaticClass.class)
  public void testDoExecute() throws Exception {
    ...
    PowerMock.mockStatic(StaticClass.class);

    expect( StaticClass.doStuff( param ) ).andReturn( "yo!" );
    replay( StaticClass.class );

    //test some stuff!
  }
}



PowerMock and Multiple Classes

To mock methods from multiple classes, you will need to amend the '@PrepareForTest' annotation, just passing a string array like so:



public class MyPowerMockSuite extends PowerMockSuite {

  public static TestSuite suite() throws Exception {
  
    return new PowerMockSuite(AwesomeTest.class);
  }
 
  public static void main(String[] args) throws Exception {
  
    junit.textui.TestRunner.run( suite() );
  }  
}

public class AwesomeTest {

  @PrepareForTest({StaticClass.class,StaticClassier.class})
  public void testDoExecute() throws Exception {
    ...
    PowerMock.mockStatic(StaticClass.class);

    expect( StaticClass.doStuff( param ) ).andReturn( "yo!" );
    replay( StaticClass.class );

    PowerMock.mockStatic(StaticClassier.class);

    expect( StaticClassier.doStuff( param ) ).andReturn( "yo!" );
    replay( StaticClassier.class );

    //test some stuff!
  }
}


Gotchas

PowerMock 1.3.7 only works with EasyMock 2.5.2, which we have had some issues with.  I had to move back to PowerMock 1.2.5 to use EasyMock 2.4.  I didn't find a lot of issues with using this version, though we had some odd calls that were required where it told me not to stub a return when the method returned something, or where I had to stub out calls that didn't seem like they should be required.  With a simple static method that didn't really call many other static methods, it seems to work like a charm.

blog comments powered by Disqus