Mockito: Effective Partial Mocking

Sometimes, we may only want to partially mock an object to unit test our code. There are several ways to skin this cat, but I’ll show two straightforward approaches that allow you to obtain the cat fur.

PROBLEM

Let’s assume we want to test this service class:-

public class CalculationService {

    public int getFirstValue() {
        return 1;
    }

    public int getSecondValue() {
        return 2;
    }

    public int getComputedValue() {
        return getFirstValue() + getSecondValue();
    }
}

Basically, getComputedValue() sums up getFirstValue() and getSecondValue() and returns the value.

PARTIAL MOCKING USING mock(...)

Here’s an example of using mock object:-

CalculationService calculationService = mock(CalculationService.class);
when(calculationService.getFirstValue()).thenReturn(2);
when(calculationService.getSecondValue()).thenReturn(5);

int val = calculationService.getComputedValue();

assertThat(val, is(???)); 

What do you think the value for ??? should be?

If you think the value is 7, you are not skinning the cat correctly.

The correct value is 0. In the above example, when we execute calculationService.getComputedValue(), we are actually executing a stub API from the mock object that doesn’t do anything but to return a default value, which is 0.

The good news is Mockito provides thenCallRealMethod() that allows us to execute the actual method instead. So, to fix this, we do something like this:-

CalculationService calculationService = mock(CalculationService.class);
when(calculationService.getFirstValue()).thenReturn(2);
when(calculationService.getSecondValue()).thenReturn(5);

when(calculationService.getComputedValue()).thenCallRealMethod();

int val = calculationService.getComputedValue();

assertThat(val, is(7));

PARTIAL MOCKING USING spy(...)

Another way to do partial mocking is to use a spy. Here’s an example:-

CalculationService calculationService = spy(new CalculationService());
when(calculationService.getFirstValue()).thenReturn(2);
when(calculationService.getSecondValue()).thenReturn(5);

int val = calculationService.getComputedValue();

assertThat(val, is(7));

WHICH IS A BETTER WAY?

It is difficult to say which approach is better because it all depends on the object we are testing. My rule of thumb is if we only want to modify the behavior of small chunk of API and then rely mostly on actual method calls, use spy(...). Otherwise, use mock(...).

In another word, when we start skinning a cat and it starts to bleed like crazy and scratch your face, sometimes, it’s wise to put down the knife and consider taking a different approach to solve the problem… metaphorically speaking.

Advertisements

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