Partial Mock is Your Friend

UPDATE: Mockito now supports real partial-mock since 1.8.0

Rhino-Mock has one dangerous ability that I find useful from time to time, known as partial-mock.
Right now, I’m working on a Java project using Mockito, and I find it “deliberately” lacking this dangerous yet delicious ability.
Mockito has spy method which is quite similar as partial mock, except that it is not. Here’s what I’m talking about

public void canGetAWarmWelcome()
{
	SUT sut = spy(new SUT());
	when(mock.getName()).thenReturn("Darling");
	
	assertEqual("Darling", sut.getName());
	assertEqual("Hello, Darling", sut.getWarmWelcome());
}

public class SUT
{
	public String getWarmWelcome()
	{
		return "Hello, " + this.getName();
	}

	public String getName()
	{
		return "Hendry";
	}
}

Using partial mock, both assertions in this test-class would pass. Using mockito spy, however, the second assertion will fail. I.e., you can’t invoke a spy method from the real SUT method from same object.

This is mostly by-design decision on Mockity side. The author argues that partial mocking smells fishy, and that it’s better to refactor the code and eliminates the need for partial-mocking.
I don’t completely agree. There are many occassions where partial-mocking can be useful particualrly when you are dealing with third party API.
I am trying to write a unit-test over a web-service client code using axis. Part of the code are autogenerated from WSDL, and I can’t refactor it to suit my unit-test.
As a brief picture, here’s the autogenerated the class I’m trying to mock (partially).

public AccountServiceBindingStub extends Stub implements AccountService_PortType
{
	public AccountDetailResponse getAccountDetail(AccountQueryRequest accountQueryRequest)
	{
		Call call = createCall();
		call.setOperationName(new QName("", "getAccountDetail"));
		/*
		call.setxxxx(...);
		call.setxxx(...);
		*/
		
		call.invoke(param);
	}
	
	protected Call createCall()
	{
		Call call = new Call();
		/*
		etc etc
		*/
	}
}

That little naughty call to “new Call()” closes the door for dependency injection. It makes it impossible for me to sneak in a fake Call instance that returns a stubbed constant string of SOAP response, substituting for making a real HTTP connection to the actual back-end.
Before you ask, I know you might be wondering why I want to involve autogenerated classes into the equation of my unit-test. Shouldnt I be mocking this whole class altogether and stub the AccountDetailResponse object directly (rather than stubbing the SOAP message)? Afterall, I’m not trying to test classes that is autogenerated by axis tool. Or am I?
The reasoning behind this is down to idiosyncrasies we have been facing in transforming SOAP message to domain model, which is exactly what we want to cover in this unit-test. For instance, cents/dollar units, negative/possitive balance sign, with/without currency symbols, PREPAID vs prepaid, and other more subtle issues. So we want to capture several actual SOAP response samples the server provides, and write some test-cases against them.
And yes, I could just write subclass of the class above, and override createCall(). But I have lots of those classes, and I don’t want to pollute my test-cases with obscure technical detail of how I fake the Call.
So I wanted to encapsulate this hacky faking-logic to a test helper that generates the runtime subclasses for me… which is precisely a partial-mock by definition (or reinventing thereof)

Advertisements