Saturday, December 17, 2011

Java - JUnit Partial Mocking using Mockito

I recently started writing a lot of JUnits as part of the development activities. Explored working with ATGDust, EasyMock and Mockito frameworks for various reasons. ATGDust for testing ATG Components, EasyMock and Mockito for writing JUnits using Mocking.

In this post, I am going to try and provide a sample to partially mock the objects (using Mockito) under test.

Need for partial Mocking - Most of the time when we write test classes to test the various methods in the class we use Mocks to make sure that the class/method is tested without much dependencies, assuming that the dependencies will be tested by their own test classes. Mocks are a great help for this situation and I think they are doing their job perfectly. But usually when you use mocks, you can only mock the dependent classes/interfaces and not really mock the class to be tested, because there is no point if you mock even class to be tested. Agreed. But there could be situations where there are too many dependencies for a particular method with other methods in the same class and you would run into a situation where you have to provide write a lot of test code before you could even invoke the method under test and see a Junit run. Partial mocking helps in situations like this, where it can mock some of the method invocations and return whatever responses you want to provide instead of executing the dependent method themselves but still allowing the real implementations to be called for the rest.


For example in the code below, MainClass has three methods - method1, method2 and method3. Assume method1 here is dependent on some external interface, you can mock that up and test method1, but if you have to test method2 and method3 you still have to do the same and also take care of other dependencies if method2 and method3 were dependent on some external interfaces. This is really time taking and tiring.

/**
 *
 */
package com.demo;

/**
 * @author Naga Seshadri
 *
 */
public class MainClass
{

  public String method1()
  {
    // some external invocations
    return "Main Class method1 called";
  }

  public String method2()
  {
    String method1Response = method1();
    return method1Response + ", Main Class method2 called";
  }

  public String method3()
  {
    String method2Response = method2();
    return method2Response + ", Main Class method3 called";
  }
}
To avoid the issue, Mockito provides a way in which you can invoke method2 for test without really calling method1's real implementation but fake it, also you can invoke method3 for test without really calling method1 and/or method2's real implementation, which is called partial mocking as illustrated by the code sample MainClassTest below

package com.demo;

import static org.mockito.Mockito.*;
import junit.framework.TestCase;

import org.junit.Test;

public class MainClassTest extends TestCase
{

  private MainClass mainClassObj;
  private MainClass mainClassSpy;

  @Override
  protected void setUp() throws Exception
  {
    super.setUp();
    mainClassObj = new MainClass();
    mainClassSpy = spy(mainClassObj);
  }

  @Test
  public void testMethod1()
  {
    System.out.println(mainClassSpy.method1());
  }

  @Test
  public void testMethod2()
  {
    doReturn("Main Class Spy method1 called").when(mainClassSpy).method1();
    System.out.println(mainClassSpy.method2());
  }

  @Test
  public void testMethod3()
  {
    doReturn("Main Class Spy method1 called").when(mainClassSpy).method1();
    System.out.println(mainClassSpy.method3());
  }
}


Here is the console output. In this case if you notice we spyed on the object on which we are calling the real methods and stubbed a couple of internal method calls which is very handy. Even though this is good we may not have a good way of doing this when you have private methods being invoked from within you public calls.

Main Class method1 called
Main Class Spy method1 called, Main Class method2 called
Main Class Spy method1 called, Main Class method2 called, Main Class method3 called

2 comments:

  1. So do you suggest Mockito over ATG - Dust for unit testing classes in an ATG project?

    ReplyDelete
    Replies
    1. ATG Dust can be used if you want to test along with the configurations and stuff, but it starts the nucleus for testing every Test case which might become a little too heavy when you have a lot more test cases. Mockito did the job for me in my case. No conclusions here, it purely depends on your requirement.

      Delete