Welcome to the second installment of my EasyMock Fundamentals series where I take you through the ins and outs of the open source Java library, EasyMock. EasyMock can be used in conjunction with a unit testing framework, such as JUnit or TestNG, to facilitate better unit testing without all the 2nd degree dependency issues. EasyMock provides the means (through the use of mock objects) to specify the response that will be returned when the code being tested makes calls to external methods. This will allow the result of the unit test to be isolated from variables outside of the scope of the unit test code.

Mocking Objects

Basic steps for EasyMock use

1. Import EasyMock

  • import static org.easymock.EasyMock.*;  // non-static imports may also be used

2. Create mock object

  • private ClassOrInterface mock;
  • mock = createMock(ClassOrInterface.class);  // throws AssertionErrors for all unexpected method calls
  • mock = createNiceMock(ClassOrInterface.class);  // allows all method calls and returns appropriate empty values (0, null or false)

3. Specify expectations for mock (in other words, “I’m going to tell you what you should expect to do”)

  • mock.doThis();
  • mock.doThat();
  • specify that the last method could be called x times
    • expectLastCall().once();  // default one call
    • expectLastCall().times(3);  // exact calls
    • expectLastCall().times(2, 5);  // min, max calls
    • expectLastCall().atLeastOnce();  // one or more times
    • expectLastCall().anyTimes();  // 0 or more times
    • specify method response or return value
      • expect(mock.doThis()).andReturn(returnValue, i.e. “true”);

4. Make mock available for use (in other words, “I’m done telling you what you should expect to do, now get ready to do it.”)

  • replay(mock)

5. Run unit test that will call doThis() and doThat()

  • verify proper response
    • assertTrue(doThis());

6. Verify that expected behavior was called (did everything get called the expected number of times?)

7. Verify(mock)

Tips

Prefer Nice Mocks

There are basically 3 different ways to have EasyMock create a mock object for you.

  1. createMock(Foo.class)
  2. createNiceMock(Foo.class)
  3. createStrictMock(Foo.class)

Each way gives you a mock object with slightly different behaviors/restrictions. Consult the EasyMock API for specifics, but unless you have valid reason to not, the preferred method is createNiceMock(). Nice mocks are, as their name suggests, ‘nice’. ‘Forgiving’ is probably a more appropriate term in that, as the API states, nice mocks will return 0false, or null for unexpected invocations. Meaning:

  • for methods that return intdoublelongcharfloatbyteshort (non-boolean primitives) – the returned value is 0
  • for methods that return boolean (not sure about Boolean) – the returned value is false
  • for methods that return Object (or anything that extends Object) – the returned value is null

The benefits are not obvious without further explanation. Try to think of it in these terms. Nice mocks allow you to configure them the way you want for the behavior you care about without having to configure them for the behavior you don’t care about and are not relying on for your test. For example, let’s assume you want a mock for an object that has a getId() method. Chance are you don’t care what getId() does and if the code you’re testing doesn’t care what it does, but happens to call it in a log statement or something that is irrelevant to your test, then a nice mock will allow you to not have to setup an expectation for that method (see Example 1).

package com.partnet.foo;
public class Foo {
  private Emailer emailer;
  public void doSomethingCool() {
    // I don't care about this and don't want to setup an expectation for it
    log.debug("emailerId:" + emailer.getId());
    // something worthy of being unit tested
    emailer.sendEmail(...);
  }
}

Additionally, if another developer were to remove that log statement, the unit test wouldn’t have to change because the expectation was never added and the tests wouldn’t break just because a log statement was removed.

Prefer “Relaxed” Expectations

The term “relaxed” refers to the IExpectationSetters API as it relates to configuring the number of times an expectation is valid. Specifically, the methods once()times(count), and times(min, max) should be avoided unless you really care and/or your test relies on them. The methods anyTimes() and atLeastOnce() should be used instead. These “execution count” methods set the number of times a given method is expected to be called. The reason the latter methods should be preferred is that, while setting up explicit method call counts is certainly valid, implementations change over time and often times those changes have no effects on the functionality of a given object. For example, who cares how many times emailer.getId() is called in the above example and does the fact that it gets called multiple times have any effect on the calling code? Clearly not. However, if an expectation like the following was added:

EasyMock.expect(mockEmailer.getId()).andReturn(1).once();

and later the log statement was removed or an additional log statement was added that called getId() again, the unit test would fail.

However, this practice is not an across-the-board standard as it makes sense to setup an expectation like the following:

EasyMock.expect(mockEmailer.sendEmail(...)).andReturn(true).once();

because sending multiple emails is most likely not expected or okay.

Please note that not specifying one of the “execution count” methods is the same as using the once() method (i.e. once() is assumed unless otherwise instructed).

Stub Returns

andReturn() vs. andStubReturn()

EasyMockSupport

Introduced in version 2.5.2, EasyMockSupport is your friend. It saves you the trouble of having to call reset()replay(), and verify() on all your mock objects. As the javadoc shows, an example usage is as follows:

package com.partnet.foo;
public class TestFoo
  extends EasyMockSupport {  // this is key
  @Test
  public void test() {
    resetAll();  // reset all existing mocks
    // create mocks
    firstMock = createMock(A.class);
    secondMock = createMock(B.class);
    replayAll();  // put all mocks (new & existing) in replay mode
    // use mocks
    verifyAll();  // verify all mocks (new & existing)
  }

This is the second in my three-part EasyMock Fundamentals series. Please leave your questions or comments in the comment section below and be on the lookout for the final installment next week.

Quick Links

EasyMock Fundamentals — Part 1

EasyMock Fundamentals — Part 3