Monday 6 June 2011

EasyMock for Unit Tests

What is mock object?
A mock object is a dummy interface or class in which you define the dummy output of a certain method call. These objects can be provided to the class which should be tested to avoid any dependency to external data. The classical example is a mock object for a data provider. In production a real database is used but for testing a mock object simulates the database and ensures that the test conditions are always the same.

What is easy mock?
This basic requirement of creating mock object can be accomplished by using Easy mock. Easy mock is a library that helps to dynamically create mock objects. This way we can avoid much of the tedious work involved in manually coding mock objects. However, EasyMock itself is not the silver bullet, we still have to define expectations in test cases. Using EasyMock also means that you have make certain design changes (if your design follows the usual design principles you may not have to change much. Here's a sample Unit Test using EasyMock. You can download easymock from here.
Class Under Test
DateFormatter.java
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateFormatter {
public static final String DATE_FORMAT = "MM/dd/yyyy";

private DateFormatterHelper helper = null;

public DateFormatter() {
}

public String convertToStandardFormat(String dateString, String format)
throws ParseException {
if (dateString == null || dateString.equals(""))
return "";
dateString = dateString == null ? "" : dateString;
DateFormat df = helper.getDateFormat(format);
Date date = df.parse(dateString);
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
return sdf.format(date);
}

public DateFormatterHelper getHelper() {
return helper;
}

public void setHelper(DateFormatterHelper helper) {
this.helper = helper;
}
}

Testing the class

Helper Class and Interface: If you are to mock any class using EasyMock, it is required that you have an interface for the class. If you are following the old design principle "program to an interface, not an implementation", you are good here.

package sample;

import java.text.DateFormat;

public interface DateFormatterHelper {
public DateFormat getDateFormat(String format);
}

DateFormatterHelperImpl.java
public class DateFormatterHelperImpl 
implements DateFormatterHelper {

public DateFormatterHelperImpl() {
}

public DateFormat getDateFormat(String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setCalendar(Calendar.getInstance());
sdf.setLenient(false);
return sdf;
}


public static void main(String args[]) {
DateFormatterHelper helper = new DateFormatterHelperImpl();
try {
System.out.println(helper.
getDateFormat("MM/dd/yyyy").parse("11/27/2008"));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

}

DateFormatterTests.java
import static org.junit.Assert.fail;

import java.text.ParseException;
import java.text.SimpleDateFormat;

import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import sample.DateFormatter;
import sample.DateFormatterHelper;

public class DateFormatterTests {

private DateFormatter formatter = null;

DateFormatterHelper helper = null;

@Before
public void setUp() throws Exception {
helper = EasyMock.createMock(DateFormatterHelper.class);
formatter = new DateFormatter();
formatter.setHelper(helper);
}

@Test
public void testConvertToStandardFormat() {

String formatted = null;
try {
EasyMock.expect(helper.getDateFormat("MM-dd-yyyy"))
.
andReturn(new SimpleDateFormat("MM-dd-yyyy"));
EasyMock.replay(helper);
formatted = formatter.
convertToStandardFormat("11-27-2008", "MM-dd-yyyy");
} catch (ParseException e) {
e.printStackTrace();
fail("Exception");
}
Assert.assertEquals(formatted, "11/27/2008");

}
}

Note that in the EasyMock.expect method line, we use the "andReturn" method. This is to define the expected behavior when the method under test is invoked by the testcase. As can be expected, the replay method simply replays the pre-defined behavior when the actual call is made on the mock object.

Download the source
You can download the source code from here.

No comments:

Post a Comment