Skip to main content

Section 11.3 Mocking frameworks: Mockito

Mocking frameworks are libraries who provide you with the tools to easily create mocks. But why use one of these libraries if making mocks is fairly easy?
  • You will end up with a large number of small mock classes sprawled all over your test code, even if you keep them within their own test files that’s still a lot of classes. Mocks from mocking frameworks are dynamically generated so they don’t pose the same problem.
  • Some times, especially when the original code wasn’t built to use interfaces, introducing manual mocks is a lot of work. Mocking frameworks can typically fake even real classes, and not just interfaces. For example in the original version of Summary, which relied in the GradeReader class, we could have used a mocking framework to fake that GradeReader.
  • Expressing what behavior you expect can be particularly nice with a good mocking framework.
Let’s take a look at one particular framework, Mockito
 1 
site.mockito.org/
. I am not endorsing or recommending it over other frameworks, but it is the one I am most familiar with and it makes it fairly easy for me to explain the concepts I am trying to explain.
You need to first incorporate Mockito into your project. After you have done that, you can use it in tests. Here is a use of it for our Summary class test:
public void correctlySummarizeOneCourse() {
  Iterator<Grade> reader = mock(Iterator.class);
  when(reader.hasNext()).thenReturn(true, false);
  when(reader.next()).thenReturn(new Grade("A"), null);
  Summary summary = new Summary(reader);
  assertEquals("Courses: 1\nGPA: 4.00\n", summary.invoke());
  verify(reader, times(2)).hasNext();
  verify(reader, times(1)).next();
}
So let’s see what is going on:
  • We create a new mock with the mock(...) method. It needs to be given the class or interface to mock, you obtain this from the actual class/interface by appending .class. In this case we are mocking something with generics, so you have to contend with some compiler warnings that we won’t go into right now.
  • You can then use when(...).thenReturn(...) to specify stubbing behavior for this mock: What it should return for specific calls. In our case I tell it that when hasNext is called, it should return true the first time and false the second time (and subsequent times). And when next is called it should return the grade the first time, and null after that.
  • We can provide spying/mocking behavior by adding the verify lines after the invoke action. These can be used to verify that certain mock methods were called, and possibly with specific arguments or possibly a specific number of times. In this case I assert that hasNext was called exactly twice, and that next was called exactly once. Technically this is not an important part of this particular test, but it shows the general approach.
This was a very quick introduction to using Mockito to write and use mocks. Before we move on, let’s take another look at the example we wrote above. We talked about how our test relies on the Grade class being implemented correctly. Let’s remove that dependency. What do we really need of that Grade object that we gave it? We need:
  • It counts for 1 unit of credit.
  • It corresponds to 4.00 points.
Instead of relying on Grade converting the letter grade of "A" to those two pieces of information, we can create a mock instead. Here’s how that test might look like:
public void correctlySummarizeOneCourse() {
  Grade grade = mock(Grade.class);
  when(grade.getCredits()).thenReturn(1);
  when(grade.getPoints()).thenReturn(4.00);
  Iterator<Grade> reader = mock(Iterator.class);
  when(reader.hasNext()).thenReturn(true, false);
  when(reader.next()).thenReturn(grade, null);
  ...
This new Grade object acts purely as a stub, providing the pertinent values to our test. It does not use the method implementations from the Grade class, because we told it how to behave instead. It only uses the type of Grade.
We could even extract it to a little helper method:
private Grade gradeMock(int credits, double points) {
  Grade grade = mock(Grade.class);
  when(grade.getCredits()).thenReturn(credits);
  when(grade.getPoints()).thenReturn(points);
  return grade;
}
....
....
    when(reader.next()).thenReturn(gradeMock(1, 4.00), null);
We could even easily move some of these more &quot;generic&quot; mocks into their own helper class, so they can be shared between tests. Perhaps the above example is a bit extreme, I will let you decide. But do you really want your test for the Summary class implementation to rely on the fact that the letter A corresponds to the gpa of 4.00? Is that really something relevant to the Summary class’ operation? Or only to the Grade class’?