Wednesday, August 11, 2010

How to test a class that directly uses java.rmi.Naming

While in the process of doing a handover of a project, some pieces of the projects source do not comply with the code standard. In this holiday season the original developer wasn't available, so I made my sleeves wet and hands dirty again, and started fixing it.

The major thing the code lacked was a proper unit test with coverage higher than 80%, well it didn't have a unit test at all.
Adding a unit test normally is not a big deal, but in this case, the class, a simple servlet that connects to a remote RMI object and calls a status method on it, directly uses java.rmi.Naming.
java.rmi.Naming is notorious for its static methods, which are hard to mock when unit testing.
There are great products out there, like powermock that can actually mock static methods, but not in system classes.
I could change the servlet code and provide a wrapper around accessing the java.rmi.Naming class, but I didn't want to change the code.

Instead I chose to not mock java.rmi.Naming, but instead just create my own instance:
@BeforeClass
public static void initNamingRegistry() throws RemoteException {
// Create a local registry with an arbitrary port number
rmiRegistry = LocateRegistry.createRegistry(9901);
This registry is alive and kickin' during the execution of my test suite, so I can now register the mock object that implements the remote business interface:
@Before
public void registerRemoteMock() throws Exception {
// Register the mock of the remote business object
rmiRegistry.bind("testName", remoteMock);
}
Then the actual servlet method can bet tested:
@Test
public void testSomeBehaviour()
// Prepare the mocks
when(requestMock.getParameter("name").thenReturn("val");
...
// Call the test method
testObject.doGet(requestMock, responseMock);

// Verify the calls if needed
verify(remoteMock).doIt();
Nice, clean and simple!

No comments: