Mocking tutorial. Part 2: Mockito

You might remember from the previous post that we are discovering the possibilities of different mocking frameworks. In the first part of this post series, I was presenting several features of JMock. In the second part we are going to see how those features are similar/different in another popular mocking framework, namely Mockito.

The example through which we exemplify the soul Mockito, is the very same we used for JMock. If you -somehow- don’t remember our example code, then you can find it below:

public class DocumentReader {

	private final Logger logger;
	private final Document document;

	public DocumentReader(Logger logger, Document document) {
		this.logger = logger;
		this.document = document;

	}

	public DocumentContent getWholeDocument() {
		DocumentContent documentContent = null;
		logger.log(Level.SEVERE, "getWholeDocument got called");
		document.openDocument();
		try {
			documentContent = readDocumentSections();
		} catch (DocumentException documentException) {
			logger.log(Level.SEVERE, "DocumentException caught in documentReader.getWholeDocument(Document)");
		} finally {
			document.closeDocument();
			logger.log(Level.SEVERE, "getWholeDocument left");
		}
		return documentContent;
	}

	private DocumentContent readDocumentSections() throws DocumentException {
		DocumentContent documentContent  = new DocumentContent(document.getDocumentTitle());
		int sectionCounter = 0;
		while (!document.documentEndReached()) {
			Section currentSection = document.getSectionBySectionNumber(sectionCounter++);
			documentContent.addSection(currentSection);
		}
		return documentContent;
	}

	public String getDocumentTitle() {
		return document.getDocumentTitle();
	}
}

Document is an empty class, it does not do anything, just defines some methods:

package impl;

public class Document {

	private final String path;

	public Document(final String path){
		this.path = path;

	}

	public void openDocument() {
		//...
	}

	public boolean documentExists() {
		//...
		return true;
	}

	public void closeDocument() {
		//...
	}

	public Section getSectionBySectionNumber(final int sectionNumber) throws DocumentException{
		//...
		return new Section();
	}

	public boolean documentEndReached() {
		return false;
	}

	public String getDocumentTitle() {
		return "Title";
	}
}

DocumentContent is just a simple data holder class:

package impl;

import java.util.ArrayList;
import java.util.List;

public class DocumentContent {

	private final String documentTitle;
	private List<Section>sections = new ArrayList<Section>();

 public DocumentContent(String documentTitle) {
 this.documentTitle = documentTitle;
 }

 public void addSection(Section newSection) {
 sections.add(newSection);
 }
}

All the other referenced classes are empty.

Now, as TDD believers, we can create a new JUnit test case. Let’s call it DocumentReaderTestMockito, in order to be consistent with the naming convention used in the previous post. After the creation of the new file, -as a first step- we have to let the test runner know that we are using Mockito. It is quite similar to what we’ve done in the last post; namely annotate the class with the @RunWith(MockitoJUnitRunner.class) annotation. After this step, you can have something like this:

@RunWith(MockitoJUnitRunner.class)
public class DocumentReaderTestMockito {

}

When using Mockito, you don’t need to create a special object, through which you can create mock object. These mocks can simply be injected automatically, using the @Mock annotation. Remember that you have to annotate your test class with the @RunWith annotation, or the automatical mock injection will not be working.
So, in order to create mock objects with Mockito, you simply need to have something like this:

@RunWith(MockitoJUnitRunner.class)
public class DocumentReaderTestMockito {

	@Mock
	Document document;
	@Mock
	Logger logger;
}

If this was a contest of user-friendliness, Mockito would have the lead over JUnit (that’s it; Mockito is simpler from this point of view). Now, we can write a test case, which (like at the last time) throws an exception when the second Section object is being read. In order to do something like that, you might have something like this:

@RunWith(MockitoJUnitRunner.class)
public class DocumentReaderTestMockito {

	@Mock
	Document document;
	@Mock
	Logger logger;

	@Test
	public void shouldThrowExceptionWhileReadingDocument() throws DocumentException {
		DocumentReader documentReader = new DocumentReader(logger, document);
		when(document.getSectionBySectionNumber(2)).thenThrow(new DocumentException());
		documentReader.getWholeDocument();
	}
}

Quite simple, huh? We just create our mock objects using dependency injection, pass them to the class under test’s instance, and tell Mockito when we want the exception to be thrown. If you look at the code, you may spot that the only Mockito-realted line inside the test case is the following: when(document.getSectionBySectionNumber(2)).thenThrow(new DocumentException());. I don’t think this line needs further comments. It is kind of straight forward. One thing to remember -exactly as in the case of JMock – Mockito returns default objects for method calls. This means zeroes, empty collections and nulls – depending on the return type of the method.

As you may have already noticed, Mockito doesn’t require you to take care of all the method calls on your mock objects. You just tell the desired interactions and you are done. Of course, if you want Mockito to return specific values, you can do that. Let’s take an example. The following test case will test the normal execution flow; the document’s end will be reached at the first call to documentEndReached().

	@Test
	public void shouldThrowExceptionWhileReadingDocument()
			throws DocumentException {
		DocumentReader documentReader = new DocumentReader(logger, document);
		when(document.documentEndReached()).thenReturn(true);

		documentReader.getWholeDocument();
	}

Or, if you want to be sure that the code is working correctly (e.g. we only leave the loop when the document’s end is reached), you just replace the “when” above, with something like this:

when(document.documentEndReached()).thenReturn(false, false, true);

Which is: for the first two invocations of documentEndReached(), we return false, while for the third one we return a true (so we leave the loop).

You might remember the concept of cardinality from JMock. There is a way you can make Mockito care about the number of invocations on your mock objects. This is what the method verify() is used for. Let’s take an example:

	@Test
	public void shouldThrowExceptionWhileReadingDocument()
			throws DocumentException {
		DocumentReader documentReader = new DocumentReader(logger, document);
		when(document.documentEndReached()).thenReturn(false, false, true);
		documentReader.getWholeDocument();

		verify(logger).log(Level.SEVERE, "getWholeDocument got called");
		verify(logger).log(Level.SEVERE, "getWholeDocument left");
	}

Now, if any of the invocations are not happening, our test case will fail. Of course, you may compact the two verify statements into one, if you don’t really care about the log messages. Mockito (just like JMock) defines the concept of argument matcher. Let’s just rewrite the test case to something like this:

	BaseMatcher<Level> isLevel = new BaseMatcher<Level>() {
		public boolean matches(Object item) {
			return item instanceof Level;
		}
		
		@Override
		public void describeTo(org.hamcrest.Description description) {
		}
	};

	@Test
	public void shouldThrowExceptionWhileReadingDocument()
			throws DocumentException {
		DocumentReader documentReader = new DocumentReader(logger, document);
		when(document.documentEndReached()).thenReturn(false, false, true);
		documentReader.getWholeDocument();

		verify(logger, times(2)).log(argThat(isLevel), anyString());
	}

When using Mockito, you can match any kind of object through the method argThat(). In order to be able to match a certain type of object (Level, in our case), you have to define your own matcher. You just simply overwrite the matches() method of the BaseMatcher abstract class, and pass the newly created object to argThat() method as a parameter. There are several predefined matchers too, like anyString(), anyInt(), anySet(), and many many others.

As you can see we’ve also passed a second parameter to the verify() method, that will tell Mockito that we want that certain invocation to happen twice. times(1) is the default value, and it can be omitted like we did before.

As a final example, let’s write a test case that will define all the invocations we need (and for that let’s get back to our first example, the one which cares for exception throwing. Such a way we can compare the final solutions implemented with Mockito and JMock):

	BaseMatcher<Level> isLevel = new BaseMatcher<Level>() {
		public boolean matches(Object item) {
			return item instanceof Level;
		}
		
		@Override
		public void describeTo(org.hamcrest.Description description) {
		}
	};

	@Test
	public void shouldThrowExceptionWhileReadingDocument()
			throws DocumentException {
		DocumentReader documentReader = new DocumentReader(logger, document);
		when(document.getSectionBySectionNumber(2)).thenThrow(new DocumentException());
		
		documentReader.getWholeDocument();

		verify(logger, times(3)).log(argThat(isLevel), anyString());
		verify(document).openDocument();
		verify(document).getDocumentTitle();
		verify(document, times(2)).documentEndReached();
		verify(document, times(2)).getSectionBySectionNumber(anyInt());
		verify(document).closeDocument();
	}

Taking into account the matcher we had to write, we end up with nearly the same complexity as in the previous post. However, Mockito would not notify you if you left out any of the interaction (it would, however, fail the test case if you defined the wrong number of invocations).

Now you have an example with both Mockito and JMock, so pick your favorite and have fun.

Advertisements

Author: tamasgyorfi

Senior software engineer, certified enterprise architect and certified Scrum master. Feel free to connect on Twitter: @tamasgyorfi

4 thoughts on “Mocking tutorial. Part 2: Mockito”

  1. Hi, I am coming up to speed on Mockito and I would like to thank you for your example. Can I point out a small error? In your example you have shouldThrowExceptionWhileReadingDocument() declared as throwing a DocumentException and then have Mockito throw that exception when getSectionByNumber() is called the third time. The problem is that this method is invoked from the getWholeDocument() method which catches the exception without rethrowing. Your junit test is just passing by default. When I add: @Test(expected=DocumentException.class) the test will fail.

    The solution was to update the getWholeDocument method to throw the DocumentException:
    public DocumentContent getWholeDocument() throws DocumentException {
    DocumentContent documentContent = null;
    logger.log(Level.SEVERE, “getWholeDocument got called”);
    document.openDocument();
    try {
    documentContent = readDocumentSections();
    } catch (DocumentException documentException) {
    logger.log(Level.SEVERE, “DocumentException caught in documentReader.getWholeDocument(Document)”);
    throw documentException;
    } finally {
    document.closeDocument();
    logger.log(Level.SEVERE, “getWholeDocument left”);
    }
    return documentContent;
    }

    Thanks again for the great tutorial. I didn’t know about the @Mock annotation before I read this and will definitely make use of it.

  2. Hi,

    instead of writing BaseMatcher

    BaseMatcher isLevel = new BaseMatcher() {

    public boolean matches(Object item) {

    return item instanceof Level;

    }

    @Override

    public void describeTo(org.hamcrest.Description description) {

    }

    };

    can,t we make of use of any(Level.class)?
    so the statement would be something like this

    verify(logger, times(3)).log(any(Level.class), anyString());

    1. Hi Sam,

      Sure, in this case you can simply use the any() matcher and it’ll still run fine.

      What I wanted with the whole BaseMatcher thing was to show how you can match objects when the matching really matters. I agree that item instanceof Level is a dummy implementation, but for complex matchings you might need your own matcher.

      Thanks for highlighting that.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s