Mocking tutorial. Part 1: JMock

Today I held a mock dojo (one and a half hour) in order to introduce mocking and JMock to my audience. This post is intended to be the first part, which focuses exclusively on JMock. In the second part (I don’t know when I’ll have the time for that) I will go through the very same exercise but with Mockito.

First of all, what is mocking? Well, in the most cases a class has dependencies. Those dependencies have to be somehow broken, so we can test one and only one class at a time. In order to break the dependencies, we have several possibilities; dummies, fakes, stubs and finally mocks. Mocks are special cases of test doubles, because one has to predefine expectations on them; these expectations form a list of calls expected to be received by the mock object. Trough mocking we can isolate all the dependencies of a class, so it can be tested in isolation, without testing the functionality of the dependent classes (remember these are unit tests). For a more accurate introduction of mock objects (which is outside the scope of this post), please be referred to this article: http://en.wikipedia.org/wiki/Mock_object

In order to exemplify the whole process of mocking, we will use the following code (I know its has its issues, but anyway it’s gonna be useful to guide you through the process of mocking):

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. You just create them with an empty body, and it should be OK.
Now, we are ready to create a test case. JUnit4 should be put onto your build path, and JMock jars too. Your test case may be called DocumentReaderTestJMock.

OK, the first thing when you want to use JMock, is to create a JUnit4Mockery and tell the test runner that you are actually using JMock. I usually call these mockeries either mockery, or context. In order to create such a mockery you may want to have something like this:

@RunWith(JMock.class)
public class DocumentReaderTestJMock {

	JUnit4Mockery context = new JUnit4Mockery();
}

Now we have JMock as testrunner (see the annotation of the class) and we’ve also got a mockery. So, we could just mock any type of class, right? Wrong! JMock has originally been designed to be able to mock interfaces only. Should you try mocking a class right now, you’d get an error message telling you that only interfaces can be mocked. Fortunately, JMock defines an extension so it can mock classes too. The resulting declaration is not a beautiful one, but anyway, let’s just see how it works:

@RunWith(JMock.class)
public class DocumentReaderTestJMock {

	JUnit4Mockery context = new JUnit4Mockery() {
		{
			setImposteriser(ClassImposteriser.INSTANCE);
		}
	};
}

OK, now we are really ready to mock classes. Let’s just try it, and create a test case, which will test the exceptional path. In order to do that, we need to have an exception to be thrown while reading document content. In order to have an extra constraint, let’s suppose that our exception is thrown while reading the second section. So, we end up with something like this:

@RunWith(JMock.class)
public class DocumentReaderTestJMock {

	JUnit4Mockery context = new JUnit4Mockery() {
		{
			setImposteriser(ClassImposteriser.INSTANCE);
		}
	};

	final Document document = context.mock(Document.class);
	final Logger logger = context.mock(Logger.class);

	@Test
	public void shouldThrowExceptionWhileReadingDocument()
			throws DocumentException {
		DocumentReader documentReader = new DocumentReader(logger, document);
		final Section section = new Section();

		context.checking(new Expectations() {

			{
				allowing(logger).log(with(any(Level.class)), with(any(String.class)));
				oneOf(document).openDocument();

				oneOf(document).getDocumentTitle();
				will(returnValue("Title"));

				exactly(2).of(document).documentEndReached();
				will(returnValue(false));

				exactly(2).of(document).getSectionBySectionNumber(with(any(int.class)));
				will(onConsecutiveCalls(returnValue(section),
						        throwException(new DocumentException())));

				oneOf(document).closeDocument();
			}
		});

		documentReader.getWholeDocument();
	}
}

Now let’s go through the test case. As you can see, JMock can mock objects through the already-well-known context object. We have two mock objects, a Logger and a Document. Whenever you have such a mock object in JMock, you have to take care of the invocations on that particular mock. This means that you have to enumerate all the method calls on the mock object, along with their parameters and the number of times the methods are called (if you forget any of them, your test case will fail). This part is represented by the anonymous inner class (context.checking); Those instructions inside it have the following structure:

1.) A cardinality number and a mock object as its parameter: oneOf(mockObject), exactly(2).of(mockObject), allowing(mockObject) : By this you can tell how many times a particular method is called on a particular mock object. oneOf means that the invocation is called once and only once, exactly(2) is straightforward, while allowing() means any number of invocations. Other cardinality numbers and values: atLeast(x).of(mockObject), atMost(x).of(mockObject), never(mockObject), ignoring(mockObject). Take care when using the last one: this will completely ignore your mock object!

2.) The method called on the mock object with its parameters. These parameters can be defined two ways:

  • exact values (But watch out when passing in plain old java objects. Those objects won’t be matched unless you have defined an accurate equals() method).
  • Parameter matchers: with(any(Something.class)), with(equal(“Hello World”)). Take care! You cannot mix exact values and matchers inside an expectation. E.g. oneOf(calculatorMock).add(1, with(any(int.class))) will be invalid. It will throw an exception telling you that not all parameters were supplied in the form of matchers. Either use exact values or matchers only. If you are sure about one (or several) parameters only, you have to use the following construct: oneOf(calculatorMock).add(with(equal(1)), with(any(int.class))).

Note that this expectation:

allowing(logger).log(with(any(Level.class)), with(any(String.class)));

could be turned into a more strict one:

exactly(3).of(logger).log(with(equal(Level.SEVERE)), with(any(String.class)));

or if you don’t care about the logger at all, then you can have :

ignoring(logger);

3.) Return statement. JMock can return default values for method calls, but if you want to customize these returned values, of course yo cant. That’s what will(returnValue(aValue)) is used for. If the value you want the function to return  is not compatible with the return type of the method, you -again- get a runtime exception (It says something like tried to return AAA from a method that can only return BBB). Note that you can make JMock simulate that an exception was thrown, by using the will(throwException(new MyException())).

You can observe a very nice functionality of JMock, by looking at the lines:

exactly(2).of(document).getSectionBySectionNumber(with(any(int.class)));
will(onConsecutiveCalls(returnValue(section), throwException(new DocumentException())));

It says that getSectionBySectionNumber() is called exactly two times. When it is called for the first time a section object will be returned, while for the second time an exception will be thrown. This way you don’t have to duplicate code lines, just customize the desired return statements.

Note that the order in which invocations are arranged inside the expectation block doesn’t matter (there is a way -by using the inSequance construct- through which you can force the test runner care about the order of expectations). However, it is necessary to define the expectations before the method under test is called.

I get it all the time that “it is too tiring to write all those expectations with all the correct parameters and all the correct cardinality “. However, I think, it is actually a very good feature. There are cases when a test case can not test anything else but collaborations and, optionally the order in which methods were called. Besides, it happened several times, that I figured out performance issues thanks to JMock cardinalities. When I had to introduce an expectation like exactly(9).of(mockObject) it made clear that resource handling is somehow not efficient.

The rest of the class can be tested similarly, requiring no additional knowledge than presented above. So, be my guest, try to achieve 100% coverage.

Advertisements

Author: tamasgyorfi

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

5 thoughts on “Mocking tutorial. Part 1: JMock”

  1. Its a great material to start up with.
    Had a small doubt. Could you please tell what is Section referring to in your example. Is it a class in Java or user defined (if so then whats its content.)

  2. Well, the original idea behind that was that a Document is made from several Sections. As Document’s implementations is not important (it is only there so we can mock it), Section is not important either. It can be a fully empty class or just an interface.

    Hope it answers the question.

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