Effective Mockito Part 3

In the previous Effective Mockito post we saw how to use the @Mock Annotation to get a clean test. In this post I want to show you how to use Mockito’s spy mechanism to eliminate testing troubles with third party libraries.

Testing is one of the most important things in software development. I assume you agree with me because you decided to read this blog post ;).  It goes without saying that when we develop software we often rely on third party functionality. This does not affect our testing because we can mock objects from third party libraries thanks to Mockito. But there is one thing that always ruins my karma…

That is, static methods. And even worse, static methods that depend on runtime state. I know there are solutions like PowerMock to enable mocking statics, but I think there is a more elegant solution to avoid the troubles with statics -  without manipulating the bytecode and without adding another mocking library, as we would with PowerMock.

Let’s dive into an example to see how. First, take a look at our third party code. In this example I know that I will have to use a static method from the framework which exists in the class FancyFrameworkUtil. The only purpose of this code is to show you that I have to use it and that the third party library changes its return type magically at runtime as the comment says (this sort of thing happens way too often).

public class FancyFrameworkUtil {
 
  public static String getProperty() {
    return "some runtime property"; // this property changes at runtime ;)
  }
 
}

Let’s get to the code we want to write: a highly sophisticated type called MyObject ;). This type has only one method called isPropertySet which will become API (by this I mean the method will be added to a public interface). The method only checks to see if the value of the third party’s framework has a specific value and returns a boolean depending on the value.

public class MyObject {
 
  public boolean isPropertySet() {
    String property = FancyFrameworkUtil.getProperty();
    boolean result = true;
    if( property.equals( "some runtime property" ) ) {
      result = false;
    }
    return result;
  }
 
}

We now know that the framework method returns a value that can change at runtime but this does not mean we can’t write a test.

public class MyObjectTest {
 
  private MyObject objectUnderTest;
 
  @Before
  public void setUp() {
    objectUnderTest = new MyObject();
  }
 
  @Test
  public void testIsPropertySet() {
    assertFalse( objectUnderTest.isPropertySet() );
  }
 
}

As you can see it’s a very straightforward test. But it’s not complete because we haven’t tested what happens when the framework’s property value changes. We can’t be sure if our MyObject#isPropertySet ever returns true. I’m sure you’ve had a similar problem in the past, too.

At this point we have a choice. Introduce another framework to mock the static framework method or do something like the following. First, we need to extract the call to the third party library in a separate method in our MyObject implementation. It’s important that we change the visibility of this method to package private. This is the price we have to pay. But I don’t think its a high price because this method will not become API and is only visible in the implementation’s package. By separating the interface and the implementation into different packages this really isn’t a problem.

public class MyObject {
 
  public boolean isPropertySet() {
    String property = getProperty();
    boolean result = true;
    if( property.equals( "some runtime property" ) ) {
      result = false;
    }
    return result;
  }
 
  String getProperty() {
    return FancyFrameworkUtil.getProperty();
  }
 
}

This is all we have to do to our implementation to enable the “pseudo mocking” of the FancyFrameworkUtil‘s method. Now comes the testing, and at this point we can use a spy. A spy is a real object with one or many mocked methods. Therefore we can spy on our objectUnderTest. In our case we want to mock the getProperty method that was added last. It can look like this.

public class MyObjectTest {
 
  private MyObject objectUnderTest;
 
  @Before
  public void setUp() {
    objectUnderTest = spy( new MyObject() );
  }
 
  @Test
  public void testIsPropertySet() {
    doReturn( "some runtime property" ).when( objectUnderTest ).getProperty();
 
    assertFalse( objectUnderTest.isPropertySet() );
  }
 
  @Test
  public void testIsPropertySetWhenPropertyChanged() {
    doReturn( "foo" ).when( objectUnderTest ).getProperty();
 
    assertTrue( objectUnderTest.isPropertySet() );
  }
 
}

As you can see in the test methods, the spying in the setUp method enables us to change the return value of the framework’s method by introducing a delegation step. With this we can ensure that our method isPropertySet reacts to changes in the framework’s property.

I hope it’s now clear how to use a spy to mock static framework methods by using delegation steps. If you know alternative ways, please take a minute to share it with us in a comment. By the way, there is also an @Spy Annotation you can use. Have fun spying icon wink Effective Mockito Part 3

followme Effective Mockito Part 3

Read the other Effective Mockito posts:

 

5 Responses to “Effective Mockito Part 3”

  1. Marcus K. says:

    And one again a good example why static methods block effective testing. If FancyFrameworkUtil was an object instead of a class, it could have easily been replaced by a Mockito stub. Yes, Spys are at least a nice way to trick around cases where you depend on foreign code with static methods. But if it is all your own code, bettter refactor the util.

  2. I completely agree with you!

  3. Sam says:

    Hi,

    if you cannot refactor the util class then you can use a Delegate to hide the static nature of the util class. The delegating class would then be mocking-friendly.

    Cheers,
    Sam

  4. zero says:

    If you want to mock static methods you are missing the point of TDD. A static method increases the coupling between components, and makes impossible to replace the implementation. Maybe you can work out the problem with tricks like this in the test, but you won’t be able to do the same in the production code. If you want the change a dependecy which consists a bounch of static method, you won’t be permitted to use reflection/bytecode manipulation and other tricks to achieve this. You will have to insists the plain old setters and constructor args to pass the dependecy. But if you do the hacking in the test you are missing the feedback from it, which suggests that there is something wrong in your design.
    Please listen to the test and solve design issues with refactoring, not with test hacking. And if you are working on legacy code, just leave it for the integration test. For third party API, write a thin adapter above it, and depend on the adapter (which is mockable) and not directly on the 3rd api.

  5. Frank says:

    zero,

    in general I agree with you that you should avoid using static methods. But I don’t see how a thin adapter for third party API will unconditionally improve the situation as stated in your last sentence. You may remove the depencency from your class under test, but you will have to move it implicitly to another one that does the wiring of the adapter with your class. So if I didn’t miss the point you may just put somebody else’s problem field around the stuff… Given the additional implementation effort of the adapter solution I would decide case by case which way to go.

5 responses so far

Written by . Published in Categories: Planet Eclipse