preload
Feb 20

Anyone who ever seriously started writing unit tests will sooner or later have come to the conclusion, that it helps isolating small testable chunks of code resulting in a clean structure of methods within a class and forcing the developer to write cleaner code. This is easy as long as the tested code does not work with data or configurations that might change depending on the environment in which the test are run.

My two favourite basic rules for writing tests (Thanks uncle bob!) are

  • tests must run anywhere. (e.g. on a continuous integration server)
  • tests must run fast, so they’re fun running them.

As soon as your tests depend on a database containing specific data or a file system with a certain directory structure you’re in trouble. In my experience many programmers write test for methods that are easy to write tests for, and avoid the more complicated cases requiring setting up test data and such like.

A really cool way for decoupling tests from dependencies like this, speeding up their execution time and finally leading to a much better code coverage are mock objects.

A mock library I really enjoy using is easymock. Let me show you an example of how easy easymock (http://www.easymock.org) really is.

First include this library to your classpath: easymock.jar

In case you want to mock classes that do not implement an interface, additionally add this library: easymockclassextension.jar

Now you can start writing your isolated test making use of mock objects

Add this include to your test class:

import static org.easymock.classextension.EasyMock.*;

or this if you’re mocking interfaces:

import static org.easymock.EasyMock.*;

This is how a test could look like (example code)

@Test
public testMyServiceMethod() {

/* create a mock object of the class that has dependencies on the environment in which it’s used */
ClassToMock mock = createMock(ClassToMock.class);

/* In this example we’re going to call a method of the mocked class that returns an Object of the type ResultObject. Create a dummy object, that the method call should return later */
ResultObject resultObject = new ResultObject();
resultObject.setXyzProperty(“test”);

/* let the mock object know which method is going to be called later with which parameters. Also define the result of the method call. */
expect(mock.methodToMock(testParam)).andReturn(resultObject);

/* the class you’re testing and that’s going to make use of the mock object, ideally holds it in an instance variable, accessible by means of a setter method. It can easily be replaced with a mock. If you’re using the Spring framework for dependency injection, your classes will usually be structured this way already. */
objectToTest.setTheObject(mock);

/* GO! */
replay(mock);

/* in the object to test, call the method which is going to make use of the mocked object. */
String result = objectToTest.methodToTest();

/* some asserts which are the essence of our test */
assertEquals(“expected”, result);

/* optionally check if the mock object was used as defined before. If the method was not called as expected, verify will fail. So in addition to the asserts this enables us to test if the expected calls to the mocked object were done */
verify(mock);
}

Mock Objects will definitely help you decoupling your tests from platform dependencies. They will make your tests faster and more fun to run.

Alex

Tagged with: