Beliebte Suchanfragen
|
//

Testing and Mocking of Static Methods in Java

10.11.2011 | 4 minutes of reading time

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:

1public final class StringUtil {
2 
3   public static String nullSafeTrim(String s) {
4      return s == null ? "" : s.trim();
5   }
6}

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):

1public class StringUtilTest {
2 
3   @Test public void shouldHandleNull() {
4      assertEquals("", StringUtil.nullSafeTrim(null));
5   }
6 
7   @Test public void shouldHandleEmptyString() {
8      assertEquals("", StringUtil.nullSafeTrim(""));
9   }
10 
11   @Test public void shouldTrimWhiteSpace() {
12      assertEquals("foo bar", StringUtil.nullSafeTrim("\t\n\r foo bar \r\n\t"));
13   }
14 
15}

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:

1public interface Dependency {
2   void doSomething();
3}
4 
5public final class StringUtil {
6 
7   private static Dependency dependency;
8 
9   public static void setDependency(Dependency d) {
10      dependency = d;
11   }
12   ...
13}

Our test can inject a mock implementation like this:

1public class DependencyMock implements Dependency {
2 
3   public void doSomething() {
4   }
5}
6 
7public class StringUtilTest {
8 
9   @Before public void setUp() {
10      StringUtil.setDependency( new DependencyMock() );
11   }
12   ...
13}

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:

1public class Calculator {
2 
3   public int add(int a, int b) {
4      return MathUtil.addInteger(a, b);
5   }
6}
7 
8public abstract class MathUtil {
9 
10   public static final int addInteger(int a, int b) {
11      return a + b;
12   }
13 
14   private MathUtil() {}
15}

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:

1@RunWith(PowerMockRunner.class)
2@PrepareForTest( MathUtil.class )
3public class CalculatorTest {
4 
5   /** Unit under test. */
6   private Calculator calc;
7 
8   @Before public void setUp() {
9      calc = new Calculator();
10 
11      PowerMockito.mockStatic(MathUtil.class);
12      PowerMockito.when(MathUtil.addInteger(1, 1)).thenReturn(0);
13      PowerMockito.when(MathUtil.addInteger(2, 2)).thenReturn(1);
14   }
15 
16   @Test public void shouldCalculateInAStrangeWay() {
17      assertEquals(0, calc.add(1, 1) );
18      assertEquals(1, calc.add(2, 2) );
19   }
20}

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):

1<properties>
2    <powermock.version>1.4.9</powermock.version>
3</properties>
4 
5<dependencies>
6    <dependency>
7        <groupId>org.powermock</groupId>
8        <artifactId>powermock-module-junit4</artifactId>
9        <version>${powermock.version}</version>
10        <scope>test</scope>
11    </dependency>
12    <dependency>
13        <groupId>org.powermock</groupId>
14        <artifactId>powermock-api-mockito</artifactId>
15        <version>${powermock.version}</version>
16        <scope>test</scope>
17    </dependency>
18    <dependency>
19        <groupId>org.mockito</groupId>
20        <artifactId>mockito-core</artifactId>
21        <version>1.8.5</version>
22        <scope>test</scope>
23    </dependency>
24    <dependency>
25        <groupId>junit</groupId>
26        <artifactId>junit</artifactId>
27        <version>4.8.2</version>
28        <scope>test</scope>
29    </dependency>
30</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.

|

share post

//

More articles in this subject area

Discover exciting further topics and let the codecentric world inspire you.

//

Gemeinsam bessere Projekte umsetzen.

Wir helfen deinem Unternehmen.

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.