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!

Sunday, September 28, 2008

AJAX and Select HTML element or how I underestimated Internet Explorer.

Working on widget for selecting recommended books I used article from w3cschools. Desired functionality was simple: user changes the category so the list of books is updated without necessity to reload the page completely. I never keep in mind all technical details, that's why I always prefer to refer to respected sources for an advice. And the advice was to use AJAX in the next way:

1) Create the instance of XMLHttpRequest handling a type of browser.
2) Initialize its onreadystatechange property: xmlHttp.onreadystatechange = callbackFunction;
3) Initialize parameters of Http request: xmlHttp.open("GET", "handler.php", true);
4) Perform the request: xmlHttp.send(null);

So far so good! It seemed reasonable and I decided to apply it. Here I throw off all insignificant details. Bluntly speaking, HTML view looked like this (file ndex.html):

<html>
<body>
<div>
<script type="text/javascript" src="/select.js"></script>
<select id="select" onchange="javascript:changed();">
<option value="1">Firstly</option>
<option value="2">Secondly</option>
<option value="3">Finally</option>
</select>
</div>
<div id="advice" />
</html>

select element
It is simple Select element with associated onchange event handler represented by JavaScript function "changed( )" defined in select.js file:

var httpObject = createXMLHttpRequest();

function changed() {
var selected = document.getElementById('select');
httpObject.onreadystatechange = handleResponse;
httpObject.open('GET', '/handler.php?option='
+ selected.options[selected.selectedIndex].value);
httpObject.send(null);
}

// Handles server responses.
function handleResponse() {
if (httpObject.readyState == 4) {
var response = httpObject.responseText;
document.getElementById('advice').innerHTML = response;
}
}

// Creates new XMLHttpRequest
function createXMLHttpRequest() {
var xmlHttp;
try {
// create an XMLHttpRequest object
xmlHttp = new XMLHttpRequest();
} catch(e) {
// assume IE6 or older
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHttp");
} catch(e) {
alert("Error creating the XMLHttpRequest object.");
}
}
return xmlHttp;
}

Let's review two other functions. Firstly, createXMLHttpRequest( ) creates global instance of XMLHttpRequest depending on type of browser. Function handleResponse( ) is called every time when our server sends a response with updated status. We wait until operation is complete (httpObject.readyState is equal to 4) and immediately update the advice with message generated by the server. Here these messages are (file handler.php):

<?php
if ($_GET['option'] == '1') {
echo 'Initialize parameters of Http request';
} else if ($_GET['option'] == '2') {
echo 'Initialize onreadystatechange property';
} else if ($_GET['option'] == '3') {
echo 'Perform the request';
} else {
echo 'Exception';
}
?>

It simply takes the option set by httpObject.open(...) call and generate appropriate text by means of HTTPResponse. This text will be contained in httpObject.responseText when the response is complete.

And... Tada! I decided that my widget is ready. I've verified it in Mozilla Firefox (the best browser for software developers ;) and Opera (cool browser too). And then... Oh! I found that it doesn't work in Internet Explorer. More precisely, it works but only once. So, you can try, when user selects option 'Secondly' from the list at first time, Internet Explorer gets the response and updates the text of 'advice' HTML element. But then user may reselect different options infinitely without any result. Only F5 refreshing the page will provide one more attempt.

I was depressed. But listening to S.O.S. by ABBA brought me to life.

I couldn't leave this issue as it was because people still use IE. Nevertheless, here I should present my apologies to Internet Explorer. Actually, it was my fault that I'd been disappointed by w3cschools' article. The mistake was in order of steps of preparing and sending XMLHttpRequest. So, the fix is:

httpObject.open('GET', '/handler.php?option='
+ selected.options[selected.selectedIndex].value);
httpObject.onreadystatechange = handleResponse;
httpObject.send(null);

Here I set onreadystatechange property after initialization of HTTPRequest parameters. It is exactly what the script listed above shouts about.

Currently this widget works in all browsers I know, including IE6 and IE7. You are welcome to use it in your web projects as well!

Taking everything into consideration, listening to music is the best approach to bug fixing.