Skip to main content

Section 11.2 Manual Mocking

Many times you can write some manual mocks easy enough. Let’s do this for example for our Summary test. Here is how I would like the test to look like:
public void correctlySummarizeOneCourse() {
  OurTestDouble reader = new OurTestDouble();
  Summary summary = new Summary(reader);
  assertEquals("Courses: 1\nGPA: 4.00\n",
               summary.invoke());
  assertEquals(2, reader.timesHasNextCalled);
  assertEquals(1, reader.timesNextCalled);
}
So I am creating an instance of our test double. This is a test double very specific to this test, so it’s a private inner class. Then I create the summary instance and call invoke. Then I ask the reader object how many tines hasNext was called and how many times next was called. And here is its implementation:
private static class OurTestDouble implements Iterator<Grade> {
  int timesHasNextCalled = 0;
  int timesNextCalled = 0;
  public boolean hasNext() {
    timesHasNextCalled += 1;
    return timesHasNextCalled < 2;
  }

  public Grade next() {
    timesNextCalled += 1;
    return timesNextCalled == 1 ? new Grade("A") : null;
  }
}
So all this double does is return the grade A the first time it’s called, then nothing afterwards. And it simply keeps track of the times it’s called.
  • By having the type Iterator<Grade> that the Summary constructor needs, it acts as a dummy.
  • By returning the grade once and then nothing, it acts as a stub.
  • By remembering how many times it was called, it acts as a spy.
If we wanted it to act as a mock, we could add a method called:
public boolean verify() {
  return timesHasNextCalled == 2 && timesNextCalled == 1;
}
And replace the last two lines of our test with:
assertTrue(reader.verify());
And then we can make our two times... fields private. This way it’s only the mock that knows what should happen. When you reach the point where you want that kind of behavior, using the mocking frameworks is typically cleaner. We’ll take a look at this in the next section. But for now, creating these mocks isn’t too hard:
  • Implement the appropriate interface
  • Make the methods behave as you would have expected the real objects to behave for this test
  • Decide if you should keep track of calls via a counter or a list of arguments.