pvillega’s posterous

pvillega’s posterous

Pere Villega  //  Born in Barcelona, living in Dublin, and tagged as geek since youth. Developer in the path to becoming a software architect. I swear this is not a proper blog :)

Feb 16 / 7:26am

EasyMock

EasyMock provides Mock Objects for interfaces in JUnit tests by generating them on the fly using Java's proxy mechanism. A Mock Object is a test-oriented replacement for a collaborator. It is configured to simulate the object that it replaces in a simple way. In contrast to a stub, a Mock Object also verifies whether it is used as expected. EasyMock creates mock objects using the java.lang.refect.Proxy object. When a mock object is created, a proxy object takes the place of the real object. The proxy object gets its definition from the interface or class you pass when creating the mock. EasyMock has two sets of APIs. One is intended for creation and manipulation of mock objects that are based on interfaces, the other on classes (org.easymock.EasyMock and org.easymock.classextensions.EasyMock respectively). Both provide the same basic functionality; however classextensions does not have quite as extensive as an API as the regular EasyMock does.

Basics

Similar to JUnit a mock object in EasyMock has a life cycle of 4 steps: create, expect, replay and verify. These steps are used to record the expected behaviour of the object in the test and to validate the result. If the verify step fails the test will fail. Before creating an object with EasyMock you must know there are 3 types of objects defined:

  • Regular: A test fails if a method is called that is not expected or if a method that is expected is not called. Order of method calls does not matter.
  • Nice: A test fails if a method is expected but not called. Methods that are called but are not expected are returned with a type appropriate default value (0, null or false). Order of method calls does not matter.
  • Strict: A test fails if a method is called that is not expected or if a method that is expected is not called. Order of method calls does matter.

Creating mock objects

There are two main ways to create a mock object using EasyMock, directly and through a mock control. When created directly, mock objects have no relationship to each other and the validation of calls is independent. When created from a control, all of the mock objects are related to each other. Examples of these ways are:

Direct creation of mock objects

@Overridepublic

void setUp() {

UserDAO userDAO = EasyMock.createMock(UserDAO.class);

CustomerDAO customerDAO = EasyMock.createMock(CustomerDAO.class);

}

Creation of a mock object using a control

@Overridepublic

void setUp() {

IMocksControl mockCreator = EasyMock.createControl();

UserDAO userDAO = mockCreator.createMock(UserDAO.class);

CustomerDAO customerDAO = mockCreator.createMock(CustomerDAO.class);

}

The API to create mock objects consists on 3 versions of the method createMock, one for each type of object: createMock, createNiceMock and createStrictMock.

Recording Behaviour

Once we have created our mock objects we need to record its behaviour to be able to validate it later. There are three groups of scenarios that exist when recording behaviour: void methods, non void methods and methods that throw exceptions. Void methods are the easiest behaviour to record. Since they do not return anything, all that is required is to tell the mock object what method is going to be called and with what parameters. This is done by calling the method just as you normally would.

Code being tested

foo.bar();

String string = “Parameter 2”;

foo.barWithParameters(false, string);

Mocking the behavior

Foo fooMock = EasyMock.createMock(Foo.class);

fooMock.bar();

fooMock.barWithParameters(false, “Parameter 2”);

When methods return values a mock object needs to be told the method call and parameters passed as well as what to return. The method EasyMock.expect() is used to tell a mock object to expect a method call.

Code to be tested

String results = foo.bar();

String string = “Parameter 2”;

BarWithParametersResults bwpr = foo.barWithParameters(false, string);

Mocking the behaviour

Foo fooMock = EasyMock.createMock(Foo.class);

EasyMock.expect(foo.bar()).andReturn(“results”);

EasyMock.expect(foo.barWithParameters(false, “Parameter 2”)).andReturn(new BarWithParametersResults());

In order to be able to test that a method throws the appropriate exceptions when required, a mock object must be able to throw an exception when called.

Code to be tested

try {

String fleName = “C:\tmp\somefle.txt”;

foo.bar(fleName);

} catch (IOException ioe) {

foo.close();

}

Mocking the behaviour

Foo fooMock = EasyMock.createMock(Foo.class);

EasyMock.expect(fooMock.bar(“C:\tmp\somefle.txt”)) .andThrow(new IOException());

foo.close();

There are times where a method will be called multiple times or even an unknown number of times. EasyMock provides the ability to indicate those scenarios with the .times(), .atleastOnce() and .anyTimes() methods.

Replaying and validating

Once the behaviour of the mock objects has been recorded with expectations, the mock objects must be prepared to replay those expectations. Mock objects are prepared by calling the replay() method and passing it all of the mock objects to be replayed.

   Foo fooMock = EasyMock.createMock(Foo.class);

EasyMock.expect(fooMock.doSomething(parameter1, parameter2)).andReturn(new Object());

EasyMock.replay(fooMock);

The final step in the mock object life cycle is to validate that all expectations were met. That includes validating that all methods that were expected to be called were called and that any calls that were not expected are also noted. To do that, EasyMock.verify() is called after the code to be tested has been executed. The verify() method takes all of the mock objects that were created as parameters, similar to the replay

() method.

   Foo fooMock = EasyMock.createMock(Foo.class);

EasyMock.expect(fooMock.doSomething(parameter1,Parameter2)).andReturn(new Object());

EasyMock.replay(fooMock);

Bar bar = new Bar();

bar.setFoo(fooMock);

EasyMock.replay(fooMock);

bar.runFoo();

EasyMock.verify(fooMock);

Real example

EasyMock can be quite confusing so I add an example of a "real case" scenario on how it would be used to mock an object in a certain unit test:

     private LoginServiceImpl service;

private UserDAO mockDao;

@Before

public void setUp() {

service = new LoginServiceImpl();

mockDao = createStrictMock(UserDAO.class);

service.setUserDAO(mockDao);

}

public void testRosyScenario() {

User results = new User();

String userName = "testUserName";

String password = "testPassword";

String passwordHash = "534h345kfswd3453"; //this should be a hash of the password

expect(mockDao.loadByUsernameAndPassword(eq(userName), eq(passwordHash)))

.andReturn(results);

replay(mockDao);

assertTrue(service.login(userName, password));

verify(mockDao);

}

Credit of this text to the amazing refcard of Dzone: http://refcardz.dzone.com/refcardz/junit-and-easymock

Loading mentions Retweet

Comments (0)