Overview

Testing and Mocking of Static Methods in Java

1 Comment

Again and again I stumble upon the myth that static code is evil because it is hard to test and you can’t mock it. Architects and lead developers are telling that tale and the juniors are picking it up and repeating it: “Static code is evil. It is hard to test. You can’t mock static methods.”

THIS.IS.BULLSHIT.

I’m gonna show you why.

Testing of Static Methods

I really can’t see why static methods should be harder to test than non-static code in instance methods. Let’s have a look at the following example:

public final class StringUtil {
 
   public static String nullSafeTrim(String s) {
      return s == null ? "" : s.trim();
   }
}

To test your string util you write unit tests the same way you would do for any other code. You write them before (congrats, you are a truly agile developer), during or after implementing your code, always aiming at a high test coverage. Apply all the TDD and BDD techniques you like (as long as the support your work):

public class StringUtilTest {
 
   @Test public void shouldHandleNull() {
      assertEquals("", StringUtil.nullSafeTrim(null));
   }
 
   @Test public void shouldHandleEmptyString() {
      assertEquals("", StringUtil.nullSafeTrim(""));
   }
 
   @Test public void shouldTrimWhiteSpace() {
      assertEquals("foo bar", StringUtil.nullSafeTrim("\t\n\r foo bar \r\n\t"));
   }
 
}

You may object that your static method has dependencies to other classes and now you are lost. Well, either your unit under test encompasses these dependent classes (which increases complexity) or you mock these dependencies. “My static method uses the evil new operator. I can’t mock the dependent class”.

Well, this is true but applies also to non-static code. If your dependencies can be abstracted by an interface, you can use setter injection. Let’s assume StringUtil depends on some interface Dependency and we want to provide a mock implementation for that interface:

public interface Dependency {
   void doSomething();
}
 
public final class StringUtil {
 
   private static Dependency dependency;
 
   public static void setDependency(Dependency d) {
      dependency = d;
   }
   ...
}

Our test can inject a mock implementation like this:

public class DependencyMock implements Dependency {
 
   public void doSomething() {
   }
}
 
public class StringUtilTest {
 
   @Before public void setUp() {
      StringUtil.setDependency( new DependencyMock() );
   }
   ...
}

Mocking of Static Methods

“I’m using EasyMock or Mockito. These frameworks are not able to mock my static methods. Static code is evil”. Then you don’t know the power of the Dark Side … eh … the power of PowerMock!

PowerMock is a JUnit extension the leverages the possibilities of EasyMock and Mockito to mock static methods (and much more).

Let’s assume the following setup:

Our unit under test is the class Calculator which just delegates the addition of two integers to MathUtil which offers only static methods:

public class Calculator {
 
   public int add(int a, int b) {
      return MathUtil.addInteger(a, b);
   }
}
 
public abstract class MathUtil {
 
   public static final int addInteger(int a, int b) {
      return a + b;
   }
 
   private MathUtil() {}
}

For some obscure reason, we want to mock the MathUtil because in our test scenario the addition should yield other results than it would normally do (in real life we may mock a webservice call or database access instead). How can this be achieved? Have a look at the following test:

@RunWith(PowerMockRunner.class)
@PrepareForTest( MathUtil.class )
public class CalculatorTest {
 
   /** Unit under test. */
   private Calculator calc;
 
   @Before public void setUp() {
      calc = new Calculator();
 
      PowerMockito.mockStatic(MathUtil.class);
      PowerMockito.when(MathUtil.addInteger(1, 1)).thenReturn(0);
      PowerMockito.when(MathUtil.addInteger(2, 2)).thenReturn(1);
   }
 
   @Test public void shouldCalculateInAStrangeWay() {
      assertEquals(0, calc.add(1, 1) );
      assertEquals(1, calc.add(2, 2) );
   }
}

First of all, we use a special test runner provided by the PowerMock framework. With the @PrepareForTest( MathUtil.class ) annotation our class to mock is prepared. This annotation takes a list of all the classes to mock. In our example, this list consists of a single item MathUtil.class.

In our setup method we call PowerMockito.mockStatic(...). (We could have written a static import for the method mockStatic, but that way you can more clearly see where that methods come from.)

Then we define our mock behaiviour calling PowerMockito.when(...). In our tests we have the usual assertions.

As you can see, we are even able to mock final methods!

To run the examples, you just have to add the following dependencies to your pom.xml (assuming you are using Maven):

<properties>
	<powermock.version>1.4.9</powermock.version>
</properties>
 
<dependencies>
	<dependency>
		<groupId>org.powermock</groupId>
		<artifactId>powermock-module-junit4</artifactId>
		<version>${powermock.version}</version>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.powermock</groupId>
		<artifactId>powermock-api-mockito</artifactId>
		<version>${powermock.version}</version>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.mockito</groupId>
		<artifactId>mockito-core</artifactId>
		<version>1.8.5</version>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.8.2</version>
		<scope>test</scope>
	</dependency>
</dependencies>

Conclusion

I showed you how to write unit tests for units with static methods. This was straight forward. With the PowerMock framework, we were are able to write tests that mock static methods.

Please have a look at the PowerMock documentation to see what else PowerMock can do for you.

More content about Agile Testing

Kommentare

  • Niklas Schlimm

    Hi Mirko, PowerMock is using the class loader to that. Its on a per test bases thats why it does increase the build time (that includes automated tests) a lot. But thats not the issue – at least if your not doing a lot static methods. The issue is that static methods jeopardize the whole idea of OO. You can’t di dependency injection, no open-closed principle etc. Of course there are exceptions where its valid to write static methods, but its for the usual developer to judge that. Therefore I believe its best to avoid static methods. I will have to come up with my own post.
    Cheers, Niklas

Comment

Your email address will not be published. Required fields are marked *