Tuesday, May 19, 2009

How to mock protected method in Java

It's a very common situation when we call protected methods of a class from other methods in the same class. This article is about approach to testing such caller methods. We'll not discuss why a test is more robust and modular if it covers only functionality of enclosing method with assumptions that invoked methods satisfy their contracts. For more information about advantages of modular tests please refer to articles about TDD and JUnit testing in Java.

Let's first review some trivial example to be on the same page. There is EinsteinFormula interface below:

package com.intelrate.mockmethod;

public interface EinsteinFormula {
double kineticEnergy(double restMass, double velocity);
}

This interface states that we can get kinetic energy of some moving body if its rest mass and velocity are provided. Here is physical law describing the formula:

.

Take a look at implimentation:

package com.intelrate.mockmethod.impl;

import com.intelrate.mockmethod.EinsteinFormula;

public class EinsteinFormulaImpl implements EinsteinFormula {

static final double SPEED_OF_LIGHT = 2.99792458E8;

/**
* Calculates kinetic energy for the given object.
*
* @param restMass object's mass
* @param velocity object's velocity
* @return kinetic energy according to Einstein formula
*/

public double kineticEnergy(final double restMass, final double velocity) {
final double restEnegry = energy(restMass);
return restEnegry * (1 / Math.sqrt(1 -
(velocity * velocity) / (SPEED_OF_LIGHT * SPEED_OF_LIGHT)) - 1);
}

double energy(final double mass) {
return mass * SPEED_OF_LIGHT * SPEED_OF_LIGHT;
}
}

As you can see, there are two meaningful methods in this class. It's quite clear how to test each of them from contract point of view but technically we don't want energy method to be called in a test for kineticEnergy because it is better to assume that energy works correctly when a test for kineticEnergy runs.

If energy method was in interface we could easily mock it using nested class as it is described at the end of article about TDD but problem here is that we cannot perform fake call of energy itself. The next interface serves a technique of mocking protected methods in Java:

package com.intelrate.mockmethod.impl;

public interface MockInterface {
Object mockMethod(Object parameter);
}

It's time to see how we can use it to test kineticEnergy calculation in JUnit + JMock:

package com.intelrate.mockmethod.impl;

import static org.junit.Assert.assertEquals;

import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JMock.class)
public class EinsteinFormulaImplTest {

private final Mockery context = new JUnit4Mockery();

private MockInterface mockInterface;

private final static double DELTA = 0.001;

@Before
public void setUp() {
mockInterface = context.mock(MockInterface.class);
}

@Test
public void testKineticEnergy() {
EinsteinFormulaImpl einsteinFormula = new EinsteinFormulaImpl() {
double energy(final double mass) {
return (Double) mockInterface.mockMethod(mass);
}
};

final double restMass = 10.0;
final double velocity = 100000000.0;
final double expectedEnergy = 5.4601175017849928E16;
final double mockRestEnergy = 8.987551787368178E17;

context.checking(new Expectations() { {
one(mockInterface).mockMethod(restMass);
will(returnValue(mockRestEnergy));
} });

assertEquals(expectedEnergy, einsteinFormula.kineticEnergy(
restMass, velocity), DELTA);
}
}

The idea behind this test is simple - we provide rest mass and velocity of some physical body and expect that its kinetic energy will be equal to predefined value. At the same time we use JMock to mock our helper interface which controls that energy method was called with mass parameter and returned mockRestEnergy to the tested method.

Summarizing this idea, we've got a clear code with optimal interface and really modular test at the same time.

Cheers!