Tuesday 17 June 2014

Partial Mocks using EasyMock

Often, there arises a situation where we need to mock only specific methods of a certain object and not the entire class. Such a situation can arise when we need to test some methods of a class which are dependent on other methods. We need to mock methods on which the behavior is dependent. Solution is to use partial mocks and to mock only the required methods.

In this post, we will see how this partial mock object can be created using EasyMock. To get familiar with EasyMock, you can refer here.

This is how we can create partial mock objects.
Retailer retailer = EasyMock.createMockBuilder(Retailer.class)
.addMockedMethod("getTaxRate").createMock();
EasyMock.expect(retailer.getTaxRate()).andReturn(20);

The createMockBuilder() creates a mock retailer object with 'getTaxRate' method as mocked. We can add as many methods to mock as required.The behavior of rest of the functions remains same.

We will use the same example used in my previous post. Here is the Customer class which has retailer object as its member -
package com.nirman.easymock;

public class Customer {

 String name;
 Retailer retailer;

 public int getProductPrice(String productId) throws Exception{
  int price = retailer.getPriceForProduct(productId);
  return price;
 }
 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public Retailer getRetailer() {
  return retailer;
 }

 public void setRetailer(Retailer retailer) {
  this.retailer = retailer;
 }

}

This is the retailer class -
package com.nirman.easymock;

public class Retailer {

 private int taxes_in_percent = 10;

 public int getPriceForProduct(String productId) throws Exception {
  int price;
  if (productId.equals("101")) {
   price = getPrice(100);
  } else if (productId.equals("102")) {
   price = getPrice(200);
  } else if (productId.equals("103")) {
   price = getPrice(300);
  } else {
   price = 0;
  }
  return price;
 }

 private int getPrice(int basePrice) {
  int finalPrice = basePrice + ((basePrice * getTaxRate()) / 100);
  return finalPrice;
 }

 public int getTaxRate() {
  return taxes_in_percent;
 }
}

Note that the getPrice(int basePrice) internally calls getTaxRate(). We will mock this getTaxRate() and keep rest of the behaviour same.

JUnit-
package com.nirman.easymock;

import org.easymock.EasyMock;
import org.junit.Test;
import org.powermock.reflect.Whitebox;
import static org.junit.Assert.*;

public class TestRetailer {

 // Without any mocks
 @Test
 public void testGetPriceForProduct() throws Exception {
  Customer customer = new Customer();
  Retailer retailer = new Retailer();
  customer.setRetailer(retailer);
  int actual = 0;

  String productId = "101";
  actual = Whitebox. invokeMethod(customer, "getProductPrice",
    productId);

  int expected = 110;
  assertEquals(expected, actual);
 }

 // Partial Mock. Specific method getTaxRate() is mocked
 @Test
 public void testGetPriceForProductPartialMock() throws Exception {
  Customer customer = new Customer();
  Retailer retailer = EasyMock.createMockBuilder(Retailer.class)
    .addMockedMethod("getTaxRate").createMock();
  customer.setRetailer(retailer);
  EasyMock.expect(retailer.getTaxRate()).andReturn(20);
  EasyMock.replay(retailer);
  int actual = 0;

  String productId = "101";
  actual = Whitebox. invokeMethod(customer, "getProductPrice",
    productId);
  int expected = 120;
  assertEquals(expected, actual);
 }

}

You can find the complete source code from here.
Thanks !!

No comments:

Post a Comment