Unit Testing Using Mocks – Testing Techniques 5

My last blog was the fourth in a series of blogs on approaches to testing code, demonstrating how to create a unit test that isolates the object under test using a stub object. Today’s blog looks at what is sometimes regarded as an opposing technique: unit testing with mock objects. Again, I’m using my simple scenario of retrieving an address from a database:

… and testing the AddressService class:

@Component
public class AddressService {

  private static final Logger logger = LoggerFactory.getLogger(AddressService.class);

  private AddressDao addressDao;

  /**
   * Given an id, retrieve an address. Apply phony business rules.
   * 
   * @param id
   *            The id of the address object.
   */
  public Address findAddress(int id) {

    logger.info("In Address Service with id: " + id);
    Address address = addressDao.findAddress(id);

    address = businessMethod(address);

    logger.info("Leaving Address Service with id: " + id);
    return address;
  }

  private Address businessMethod(Address address) {

    logger.info("in business method");

    // Apply the Special Case Pattern (See MartinFowler.com)
    if (isNull(address)) {
      address = Address.INVALID_ADDRESS;
    }

    // Do some jiggery-pokery here....

    return address;
  }

  private boolean isNull(Object obj) {
    return obj == null;
  }

  @Autowired
  @Qualifier("addressDao")
  void setAddressDao(AddressDao addressDao) {
    this.addressDao = addressDao;
  }
}

…by replacing he data access object with a mock object.

Before continuing, it would be a good idea to define what exactly a mock object is and how it differs from a stub. If you read my last blog, you’ll remember that I let Martin Fowler define a stub object as:

“Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what’s programmed in for the test.”

…which is taken from his essay Mocks Aren’t Stubs.

So, how do mock object differ to stubs? When you hear people talk about mock objects, they often mention that they’re mocking behaviour or mocking roles, but what does that mean? The answer lies in the way a unit test and a mock object work together to test your object. The mock object scenario goes like this:

  1. A mock object is defined in the test.
  2. The mock object is injected into your object under test
  3. The test specifies which methods on the mock object will be called, plus the arguments and return values. This is known as ‘setting expectations’.
  4. The test then runs.
  5. The test then asks the mock to verify that all the method calls specified in step three were called correctly. If they were then the test passes. If they weren’t then the test fails.

Therefore, mocking behaviour or mocking roles really means checking that your object under test calls methods on a mock object correctly and failing the test if it doesn’t; hence, you’re asserting on the correctness of method calls and the execution path through your code, rather than, in the case of a regular unit test, the return value of the method under test.

Although there are several professional mocking frameworks available, for this example I first decided to produce my own AddressDao mock, which fulfils the above requirements. After all, how hard can it be?

public class HomeMadeMockDao implements AddressDao {

  /** The return value for the findAddress method */
  private Address expectedReturn;

  /** The expected arg value for the findAddress method */
  private int expectedId;

  /** The actual arg value passed in when the test runs */
  private int actualId;

  /** used to verify that the findAddress method has been called */
  private boolean called;

  /**
   * Set and expectation: the return value for the findAddress method
   */
  public void setExpectationReturnValue(Address expectedReturn) {
    this.expectedReturn = expectedReturn;
  }

  public void setExpectationInputArg(int expectedId) {
    this.expectedId = expectedId;
  }

  /**
   * Verify that the expectations have been met
   */
  public void verify() {

    assertTrue(called);
    assertEquals("Invalid arg. Expected: " + expectedId + " actual: " + expectedId, expectedId, actualId);
  }

  /**
   * The mock method - this is what we're mocking.
   * 
   * @see com.captaindebug.address.AddressDao#findAddress(int)
   */
  @Override
  public Address findAddress(int id) {

    called = true;
    actualId = id;
    return expectedReturn;
  }
}

The unit test code that supports this mock is:

public class MockingAddressServiceWithHomeMadeMockTest {

  /** The object to test */
  private AddressService instance;

  /**
   * We've written a mock,,,
   */
  private HomeMadeMockDao mockDao;

  @Before
  public void setUp() throws Exception {
    /* Create the object to test and the mock */
    instance = new AddressService();
    mockDao = new HomeMadeMockDao();
    /* Inject the mock dependency */
    instance.setAddressDao(mockDao);
  }

  /**
   * Test method for
   * {@link com.captaindebug.address.AddressService#findAddress(int)}.
   */
  @Test
  public void testFindAddressWithEasyMock() {

    /* Setup the test data - stuff that's specific to this test */
    final int id = 1;
    Address expectedAddress = new Address(id, "15 My Street", "My Town", "POSTCODE", "My Country");

    /* Set the Mock Expectations */
    mockDao.setExpectationInputArg(id);
    mockDao.setExpectationReturnValue(expectedAddress);

    /* Run the test */
    instance.findAddress(id);

    /* Verify that the mock's expectations were met */
    mockDao.verify();
  }
}

Okay, although this demonstrates the steps required to carry out a unit test using a mock object, it’s fairly rough and ready, and very specific to the AddressDao/AddressService scenario. To prove that it’s already been done better, the following example uses easyMock as a mocking framework. The unit test code in this more professional case is:

@RunWith(UnitilsJUnit4TestClassRunner.class)
public class MockingAddressServiceWithEasyMockTest {

  /** The object to test */
  private AddressService instance;

  /**
   * EasyMock creates the mock object
   */
  @Mock
  private AddressDao mockDao;

  /**
   * @throws java.lang.Exception
   */
  @Before
  public void setUp() throws Exception {
    /* Create the object to test */
    instance = new AddressService();
  }

  /**
   * Test method for
   * {@link com.captaindebug.address.AddressService#findAddress(int)}.
   */
  @Test
  public void testFindAddressWithEasyMock() {

    /* Inject the mock dependency */
    instance.setAddressDao(mockDao);
    /* Setup the test data - stuff that's specific to this test */
    final int id = 1;
    Address expectedAddress = new Address(id, "15 My Street", "My Town", "POSTCODE", "My Country");
    /* Set the expectations */
    expect(mockDao.findAddress(id)).andReturn(expectedAddress);
    replay();

    /* Run the test */
    instance.findAddress(id);

    /* Verify that the mock's expectations were met */
    verify();
  }
}

…which i hope you’ll agree is more progressional than my quick attempt at writing a mock.

The main criticism levelled at using mock objects is that they closely couple the unit test code to the implementation of the production code. This is because the code that sets the expectations closely tracks the execution path of the production code. This means that subsequent refactoring of the production code can break a multitude of tests even though the class still fulfills its interface contract. This give rise to the assertion that mock tests are fairly brittle and that you’ll spend time fixing them unnecessarily, which from experience I agree with – although using ‘non-strict’ mocks, which don’t care about the order in which methods expectations are called, alleviates the problem to a degree.

On the other hand, once you know how to use a framework like easyMock, producing unit tests that isolate you object under test can be done very quickly and efficiently.

In self critiquing this example code, I’d like to point out that I think that using a mock object is overkill in this scenario, plus, you could also easily argue that I’m using a mock as a stub.

Several years ago, when I first came across easyMock, I used mocks everywhere, but recently I’ve come to prefer manually writing stubs for application boundary classes, such as DAOs, and objects that merely return data. This is because stub based tests are arguably a lot less brittle than mock based tests especially when all you need to is access data.

Why use mocks? Mocks good at testing an application written using the ‘tell don’t ask’ technique, to verify that a method with a void return is called.

Reference: Unit Testing Using Mocks – Testing Techniques 5 from our JCG partner at the Captain Debug blog

Related Articles :

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


seven − 5 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close