Sunday, December 16, 2012

Unit Testing using Mockito and PowerMock


Unit Testing is a vital task in any development cycle. It involves writing tests around the actual classes and methods developed as part of the project. Mostly all the applications today involve external service calls, database calls, system calls which cannot be invoked by the unit tests as it will effect the state of the application in most circumstances. One possible solution would be to create an equivalent Test classes for such classes making external calls, using the Test Double pattern. But this increases redundant code, drives up efforts to develop unit-test counterpart of the original class and increases code maintenance. On the other hand mocking an object from the original class can be easily used to check for expected results while writing unit tests. There are many frameworks which support mocking of objects such as Mockito, PowerMock, JMock, EasyMock, SevenMock, rMock and Unitils. All the mocking frameworks use reflection mechanism and sometimes byte-code to create a mocked object mostly during runtime. The usual working of these frameworks involves following steps:
  1. Creation of a mock.
  2. Definition of the stubbed methods (what the method should do when a call happens). Sometimes definition is combined with expectations.
  3. Definition of the expectations (how many times this method will be called, etc).
  4. Execution of the test code.
  5. Verification of the expectations.

  There are various patterns and popular styles for unit testing using mock objects. The Chicago-style Testing and London-style Testing are the popular ones which preached in most of the schools. Chicago-style Testing focuses on asserting that the subject-under-test changes to the expected state. While London-style Testing focuses on writing tests by asserting that the subject-under-test does the expected calls to the components to which it must interact. London-style tests usually use mock objects to assert interactions and to isolate the subject-under-test from its dependencies, facilitating the task of testing. London-style testing is also referred as Interaction or Behavioral style TDD or mockist-style testing. Chicago-style on the other hand is also referred to as Detroit-style or classic TDD.
   Self Shunt pattern is another approach besides mocking the objects for unit testing. It is usually used to test whether an object under test communicates correctly with its collaborator i.e. to check that an object has been called correctly. With self-shunt, the test case passes itself to the object under test, the object under test then interacts with the test case, and then the test case checks its own state. Self-shunt is a specialized case of mock object pattern, where the test case itself acts as a mock. Self shunt pattern can be applied typically by creating complete stub of the object or using the test case object itself as stub. Stub objects provide canned responses (and can be autogenerated by helper libraries), but typically do not directly cause the unit test to fail unlike the mock objects. They are typically just used so that the object you're testing gets the data it needs to do its work. Self shunt pattern does violates the single responsibility principle which states that every class should handle only one responsibility. With self shunt pattern, the test stub class changes if the test case changes or if method signature of the interface it implements changes thus making the test class responsible for both the test case as well as to implement the interface. But even if the test class is mocked, the attributes of the class still must be semantically coupled with the original test class making any meaningful separation difficult.

   In real unit tests stubs are a lot more complex than dummy objects because usually it needs a way to modify the return value on the stub object. Further it starts to get really complex when the system under test requires certain methods on a collaborator to be called (possibly in a certain order). Then we need to use a mock that can record how it is used and be verified later on. Using a Test Spy, is a much simpler way to test how collaborators were used than creating a record/playback style mock. A Test Spy is a real object with one or many mocked methods. It allows to record method invocations for later verification of the behavior and stub methods.

Below is the common terminology specified in xunits-patterns used across various testing frameworks:
  • A Dummy Object is a placeholder object passed to the system under test but never used.
  • A Test Stub is a hard coded object used for testing. It provides the system under test with indirect input.
  • A Test Spy provides a way to verify that the system under test performed the correct indirect output. The verification occurs after the method under the test has been called.
  • A Mock Object provides the system under test with both indirect input and a way to verify indirect output. All the expectations are configured before the calling of the method under test.

Mockito
Mockito is one of the testing framework used to create mock objects for automated junit tests in Test-driven development or Behavioral-driven development. Mockito allows to mock both classes as well as interfaces unlike EasyMock which requires class extensions to do so. Mockito also allows to chain the method calls similar as EasyMock, producing less imperative code. Mockito also supports Hamcrest matchers allowing 'match' rules to be defined declaratively, such as assertThat() contruct and its standard set of matchers. It is primarily used for Interaction testing in order to verify the interactions between various objects.
    When using mockito for mocking objects, we don't need to specify an exact argument. We can use argument matchers such as anyString(), anyList(), anyLong(), anyMap(), anySetOf(), anyListOf() etc. Warning, If you are using argument matchers then all the arguments must be provided by matchers.
e.g. when(person.getAddress(anyInt(), eq("abc")).thenReturn("53rd Street, IL");   // FAILS

doNothing() is used to set the void methods to do nothing which generally is by default on mock objects. It is mostly used when we make consecutive calls on the method were we want alternate call to fail, or when we spy on the actual object and want the void method to do nothing.
doAnswer() is used when we want to answer the call to the stub object's void method with Mockito's generic Answer type.
doThrow() is used when we want to throw an exception when the stub object's void method is called.
doReturn() is used to when we are calling real methods on spy objects or overriding previous exception stubbing. We can specify the object to be returned when the specified stub method is called.
when() is used when we want the particular method of the mock object to return a particular value (or throw a particular exception) when it is called.
stub() is used to stub a method call with return value or an exception. It is same as Mocktio.when which is recommended over stub() method.
verify(mock) is used to check if certain behavior happened once. verify(mock, times(n)) is used to check if the certain behavior happened n number of times. Verify will work only after calling the actual method.

Further @Mock annotation is used to create a mock object similar to Mockito.mock(). The @InjectMocks annotation on the other hand is used to inject the mock or spy objects (from current class) in the specified class to instantiate an object. Currently it only supports setter injection. Mockito tries to inject the objects by type, but does not throw anything when injection fails.

Below is the required maven dependencies for using Mockito:

  <dependency>
   <groupId>org.mockito</groupId>
   <artifactId>mockito-all</artifactId>
   <version>1.9.5-rc1</version>
  </dependency>

  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.10</version>
   <scope>test</scope>
  </dependency>


PowerMock requires @RunWith(PowerMockRunner.class) annotation at the class level inorder to initialize powermock. Then @PrepareForTest annotation is required to tell PowerMock to prepare the specified classes for testing. The classes passed to @PrepareForTest annotation contains the static methods which are needed to be mocked. In order to mock a static class PowerMockito.mockStatic() is called passing the static class to be mocked. Mockito.when is used to return the expected value, do nothing or throw exception. PowerMockito.when() method can be used too which just delegates to the original Mockito.when(Object) method. The PowerMockito.doNothing() is used for setting void methods to do nothing. The PowerMockito.doCallRealMethod() method is used to called the real implementation of the static method. Static methods can be verified by first calling the PowerMockito.verifyStatic() to start verifying certain behavior followed by the call to the static method to be verfied. Mockito.VerificationMode can be used with PowerMockito.verifyStatic(Mockito.times(2)) to verify the exact number of calls on a static method. Below is the sample test using Mockito:


@RunWith(MockitoJUnitRunner.class)
public class TestHarnessWebServiceTestServiceTest {

    @Mock OrganizationAccountMapper organizationAccountMapper;
    @Mock UserService userService;
    @InjectMocks TestHarnessWebServiceTestService service;

    @Test
    public void authorizeUser_shouldThrowAnErrorIfWeFailToGetRoles() throws Exception {

      Sample sample = Mockito.mock(Sample.class);

      when(userService.getTaxDetails(anyListOf(Integer.class))).thenThrow(new ContextException(DB_ERROR));
      when(userService.login(anyString(), anyInt(), anyString())).thenReturn(null);
      when(userService.findRolesFor("userId")).thenReturn(new String[0]);

      assertEquals(true, userService.testAccountFlexOrgList("userId", "password"));
      assertSame(error, e.getCause());
      assertTrue(userService.authorizeUser("userId", "password"));

      verify(organizationAccountMapper).getRelatedAccounts(0, "1");
      verify(userService,times(2)).updateContext(organizationAccountMapper);

      service.sendMessage("userId", "Some Message");
   }
}

public class TestHarnessWebServiceTestService {

   private UserService userService;

   public void setUserService(UserService userService) {
      this.userService= userService;
   }

   public void sendMessage(String userId, String message) {
      String emailId = userService.getEmailAddress(userId);
      sendEmail(emailId, message);
   }
}

While using mockito when clause on mock/live objects, it is important to consider the following:
1) When Mockito.mock() is used and methods are called on it, none of the actual methods get called. The when clause configured works in this case.
2) When a new Object() instance is used and mockito config such as Mockito.when(....).thenReturn(....) is applied to it (object in the when clause), then this Mockito configuration does not work for the actual object. In such case a mock object needs to be injected e.g. in case of service or database objects, which will configured with mockito's when...thenReturn... clauses.

Mockito Answer is used to provide the mock object with the ability to act as a bean, by recording the value being passed to the actual method. It allows stubbing with generic Answer interface and return the same argument instance on a mocked method using Answer interface. The doAnswer() is used to stub a void method with a generic Answer and capture arguments passed for verification. The thenAnswer() method sets a generic Answer for the method and is similar to the thenReturn() method were the answer() method is executed everytime returning the value specified during the when clause.

Do Answer Example:
      Mockito.doAnswer(new Answer() {
          public Object answer(InvocationOnMock invocation) {
              Object[] args = invocation.getArguments();
              Mock mock = invocation.getMock();
              return null;
          }
      }).when(mock).someMethod();

Then Answer Example:
      Mockito.when(mock.someMethod(anyString())).thenAnswer(new Answer() {
          Object answer(InvocationOnMock invocation) {
             Object[] args = invocation.getArguments();
             Object mock = invocation.getMock();
             return "called with arguments: " + args;
          }
      });

      System.out.println(mock.someMethod("foo"));

Spy

All the methods of a spy object are real unless they are stubbed, as opposed to a mock object were all the methods are stubbed unless callRealMethod() is called. Hence spy object allows partial mocking retaining real methods of the object to be tested. Partial mocking is widely debated as it usually means that the code complexity has been moved to a different methods of the same object which generally is not considered as a best practice.

Mockito Spy Example:
      ConfigurationEvent configurationElement=Mockito.spy(new ConfigurationEvent());
      Mockito.doNothing().when(configurationElement).begin();
      Mockito.doReturn(true).when(configurationElement).isSoftDeleted();
      Mockito.doReturn(new ElementType(12,"event",true,true)).when(configurationElement).getElementType();

Matchers

Matchers provides a set of static methods which allows flexible verification and stubbing. There are two implementations of matchers, Hamcrest matchers and Mockito matchers. Hamcrest matchers are generic-typed objects that check that an arbitrary value matches specific criteria and return Matcher objects of type Matcher<T>. Mockito matchers are static methods specific to when and verify that apply only to argument values, and return object of type T. Mockito matchers often implement Hamcrest Matcher interface providing standard hamcrest methods.

BaseMatcher is a base class for all the Hamcrest Matcher implementations. Some of the frequently used hamcrest matchers include ArgumentMatcher and TypeSafeMatcher. The ArgumentMatcher is a type of hamcrest Matcher which provides a predefined describeTo() method while an abstract method matches() to be implemented. TypeSafeMatcher implements null checks and checks for specific type before casting. CustomMatcher implements the describeTo() method providing the description of the object, with the remaining methods to be implemented. BaseMatcher can be extended directly to provide custom matcher implementations. The methods to implement are matches() which evaluates the matcher for an item and describeMatch() method which generates the description providing the reasoning for non accepted item.


Matcher Example:
    private static class HealthCheckMatcher extends BaseMatcher< Healthcheck > {

        private HealthCheck expected;

        HealthCheckMatcher(HealthCheck healthCheck) {
            assert healthCheck != null;
            this.healthCheck = healthCheck;
        }

        @Override
        public boolean matches(Object item) {
            if (!(item instanceof HealthCheck)) {
                return false;
            }
            HealthCheck actual = (HealthCheck) item;
            return expected.getKey().equals(actual.getKey()) && expected.getName().equals(actual.getName());
        }

        @Override
        public void describeTo(Description description) {
            description.appendText("HealthCheck with key: ").appendValue(expected.getKey())
                    .appendText(", test name: ").appendValue(expected.getName());
        }

        @Override
        public void describeMismatch(Object item, Description description) {
            description.appendText("was ");
            if (!(item instanceof HealthCheck)) {
               description.appendValue(item == null ? "null" : item.getClass());
               return;
            }

            description.appendValue(item);

            HealthCheck actual = (HealthCheck) item;
            
            if(!expected.getKey().equals(actual.getKey())) {
               description.appendText("Key mismatch. Expected: ").appendValue(expected.getKey())
                          .appendText(", Actual: ").appendValue(actual.getKey());
            }
            // Similarly equality check for expected.getName() and actual.getName().
        }
    }

    @Test
    public void healthCheckListInitializedOnlyReturnsThoseValuesExpected() {

        HealthCheck expectedHealthCheck = new HealthCheck("354", "Pulse per minute");

        // Check if an expected item is present in the list.
        Collection< HealthCheck > list = makeSomeCall();
        Assert.assertThat(list, HealthCheckMatcher.hasItem(expectedHealthCheck));

        // Check if the actualHealthCheck object matches the expected object. 
        // This is one way match two objects without any equals() method implementation.
        HealthCheck actualHealthCheck = makeSomeOtherCall();
        HealthCheckMatcher healthCheckMatcher = new HealthCheckMatcher(expectedHealthCheck);
        Assert.assertThat(actualHealthCheck, healthCheckMatcher);
    }

ArgumentCaptor is a specialised ArgumentMatcher that records the matched argument for later inspection using the capture() method. It enables to assert certain arguments after verifying actual call. First an ArgumentCaptor is created for the class we wish to inspect. Then the ArgumentCaptor is used as an ArgumentMatcher in the verify call. No matter what values the object contains, the ArgumentCaptor will always match thus allowing the verify call to succeed. After capturing the object, its values can be inspected by calling getValue() method and the original object been passed to the actual method can be accessed.

Agrument Capture Example:
      ArgumentCaptor< alerteventpreference > modelPrefCaptor = ArgumentCaptor.forClass(AlertEventPreference.class);    
      verify(unitOfWork).registerNew((modelPrefCaptor.capture()));  
      AlertEventPreference alertEventPreference = modelPrefCaptor.getValue();
      assertEquals(CAN_ALERT_ID, alertEventPreference.getAlertEventId());

In order to Capture an argument which is an object of Collection or List interface using ArgumentCaptor gives issues due to generic typed objects. This is resolved by using the @Captor annotation as shown below:
      @Captor
      private ArgumentCaptor< List< Machine > > machineListArgumentCaptor;    
      ....  
      verify(machineListBroker).populateEmbeds(eq(ANY_ORG_ID), machineListArgumentCaptor.capture(), anyList());
      assertEquals(machineListArgumentCaptor.getAllValues().get(0).size(), 2);

PowerMock
Powermock is the testing framework extending other standard libraries such as EasyMock and Mockito. It  uses a custom classloader and bytecode manipulation to enable mocking of static methods, constructors, final classes and methods, private methods, removal of static initializers.
Below is the required maven dependencies for using PowerMock:

    <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-module-junit4</artifactId>
      <version>${org.powermock.version}</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-api-mockito</artifactId>
      <version>${org.powermock.version}</version>
      <scope>test</scope>
    </dependency>

PowerMock requires @RunWith(PowerMockRunner.class) annotation at the class level inorder to initialize powermock. Then @PrepareForTest annotation is required to tell PowerMock to prepare the specified classes for testing. The classes passed to @PrepareForTest annotation contains the static methods which are required to be mocked. In order to mock a static class PowerMockito.mockStatic() is called by passing the static class to be mocked. PowerMockito.when() method is used to return the expected value, do nothing or throw exception when invoked. Since PowerMockito.when() method just delegates to the original Mockito.when(Object) method, it can be used alternatively with Mockito.when() method. The PowerMockito.doNothing() is used for setting void methods to do nothing. The PowerMockito.doCallRealMethod() method is used to call the real implementation of the static method. Also Mockito matchers are may still applied to a PowerMock mock.

Static methods can be verified by first calling the PowerMockito.verifyStatic() to start verifying certain behavior followed by the call to the static method to be verfied. Mockito.VerificationMode can be used with PowerMockito.verifyStatic(Mockito.times(2)) to verify the exact number of calls on a static method.
Below is the sample test using PowerMock:

public class AppHelper {
 
  public static Integer getOrganizationId(String ldapID) throws HttpException {
   
    Integer organizationId = 0;
    ComponentRegistry.getInstance().getLog().writeTrace("getOrganizationId", "Retrieving org details for userid:" + 
                                                                              ldapID + " from Application");
    MaintainAccountService service = getMaintainAccountServiceProxy();

    OrgAccountsByUserIDIP orgAccountsByUserIDIP = new OrgAccountsByUserIDIP();
    orgAccountsByUserIDIP.setUserID(ldapID);
    OrgAccountsByUserIDOP response = service.getOrgAccountsByUserID(orgAccountsByUserIDIP);

    parseResponse(appController, response, businessKey);
    appPostProcess(appController,response);
 
    if(response != null && !response.getOrganizationAccount().isEmpty()){
      if(response.getOrganizationAccount().size() > 1) {
       throw new HttpException(HttpStatus.SC_PRECONDITION_FAILED,"Precondition failed");
      }
      else {
       organizationId = response.getOrganizationAccount().get(0).getId();
       ComponentRegistry.getInstance().getLog().writeTrace("getOrganizationId", "Got organization: " + organizationId + 
                                                           " for userid:" + ldapID + "     from Application");
      }
    }
   
    if(organizationId == 0){
      ComponentRegistry.getInstance().getLog().writeTrace("Organization Id is not found for the LDAP Id :"+ldapID);
    }
 
    return organizationId;
  }
  .............
}
 
@RunWith(PowerMockRunner.class)
@PrepareForTest({ComponentRegistry.class,AppHelper.class})
public class AppHelperTest {
 
  @Test
  public void powerMockTest() {

    PowerMockito.mockStatic(ComponentRegistry.class);
    PowerMockito.mockStatic(AppHelper.class);
 
    Log logMock = Mockito.mock(Log.class);
    Mockito.doNothing().when(logMock).writeTrace(Mockito.anyString(),Mockito.anyString());
    Mockito.doNothing().when(logMock).writeTrace(Mockito.anyString());
 
    ComponentRegistry registry = Mockito.mock(ComponentRegistry.class);
    Mockito.when(registry.getLog()).thenReturn(logMock);
    PowerMockito.when(ComponentRegistry.getInstance()).thenReturn(registry);
   
    MaintainAccountService service = Mockito.mock(MaintainAccountService.class);
    Mockito.when(service.getOrgAccountsByUserID(Mockito.any(OrgAccountsByUserIDIP.class))).thenReturn(createTestIP());
 
    PowerMockito.when(AppHelper.getMaintainAccountServiceProxy()).thenReturn(service);
 
    PowerMockito.doNothing().when(AppHelper.class,"parseResponse",Mockito.any(AppController.class), 
                                                  Mockito.any(OrgAccountsByUserIDOP.class), Mockito.anyString());
 
    PowerMockito.doNothing().when(AppHelper.class,"appPostProcess",Mockito.any(AppController.class), 
                                                  Mockito.any(OrgAccountsByUserIDOP.class));
 
    PowerMockito.doCallRealMethod().when(AppHelper.class,"getOrganizationId","user");

    PowerMockito.verifyStatic(AppHelper.class, Mockito.times(3));

    AppHelper.getOrganizationId("user");
  }
}

No comments: