Mockito’s partial mocks. Testing real objects just got easier

In this article (in french), I wrote 6 months ago, I was searching for a mockito-like syntax to stub only one method of an object instance under test. Mockito brought it in it’s latest version.

Here is a recap of the need:

This is what I usually write to mock a method of a real object (usually to return a mock) :

CopyFileRule rule = new CopyFileRule("src.txt", "dest.txt") {
	@Override
	protected FileTemplate createFileTemplate() {
		return mock(FileTemplate.class);
	}
};

This is clear enough but in real life, it tends to be more complex than in this example. Let’s say that CopyFileRule is Serializable, that createFileTemplate takes arguments that you’s like to check and that you use mockFileTemplate outside of CopyFileRule. Here is what the code would look like:

final FileTemplate mockFileTemplate = mock(FileTemplate.class);

CopyFileRule rule = new CopyFileRule("src.txt", "dest.txt") {
	static final long serialVersionUID = ...; // Otherwise Eclipse will complain

	@Override
	protected FileTemplate createFileTemplate(String type) {
		assertEquals("TYPE1", type);
		return mockFileTemplate;
	}
};

verify(mockFileTemplate).copy("src.txt", "dest.txt");

A little bit more confusing…

This is what I’d like to write:

CopyFileRule rule = intercept(new CopyFileRule("src.txt", "dest.txt"));

FileTemplate mockFileTemplate = mock(FileTemplate.class);
when(rule.createFileTemplate("TYPE1")).thenReturn(mockFileTemplate);

verify(mockFileTemplate).copy("src.txt", "dest.txt");

Simpler and keeps the given/when/then flow clear.

Mockito 1.8-rc1 introduces real partial mocks which are exactly that.

You create an object instance calling one of its constructors and you tell Mockito that you are willing to change some methods for this instance :

CopyFileRule rule = spy(new CopyFileRule("src.txt", "dest.txt"));

You replace a method:

when(rule.createFileTemplate()).thenReturn(mockFileTemplate);

Exactly the syntax I wanted! And it works for public AND protected methods, wether the method is called from the outside or the inside of the spied object.

Who said Mockito didn’t rule?

There is only one caveat to this syntax. The real rule.createFileTemplate() method will be called once. This can have a lot of side effects and might even fail throwing an exception (very often a NPE). To solve this, you can (should?) use this alternative Mockito syntax:

doReturn(mockFileTemplate).when(rule).createFileTemplate();

I like this syntax for partial mocks because it has no side effect and because it makes a difference between standard mocks and partial mocks.

A final warning: partial mocks should be used with caution. It’s powerful but can lead to poor design.

Shameless plug: Prototype based languages can do this natively. It might be the time to try Ioke

4 thoughts on “Mockito’s partial mocks. Testing real objects just got easier”

  1. You can write it like this with JMockit:


    FileTemplate mockFileTemplate; // declared as field or test parameter
    ...
    CopyFileRule rule = new CopyFileRule("src.txt", "dest.txt");

    new Expectations(rule) {{
    rule.createFileTemplate("TYPE1"); returns(mockFileTemplate);
    }};
    ...
    new Verifications() {{
    mockFileTemplate.copy("src.txt", "dest.txt");
    }};

    Works for all kinds of methods (even final and static) and also constructors. The real “rule.createFileTemplate” is not called.

  2. @David

    Thanks! And yes, for only one or two expectations or verifications, Mockito syntax is shorter. But notice that Mockito requires one extra method call (“when”, “verify”) for each expectation/verification, while in JMockit there is typically only one Expectations/Verifications block for each test, no matter how many individual mock invocations the test executes.

    For verifications in order, the JMockit syntax is more compact.
    For example, in Mockito you would have:

    InOrder inOrder = inOrder(firstMock, secondMock);
    inOrder.verify(firstMock).add(“was called first”);
    inOrder.verify(secondMock).add(“was called second”);

    versus in JMockit:

    new VerificationsInOrder() {{
    firstMock.add(“was called first”);
    secondMock.add(“was called second”);
    }};

Comments are closed.