Saturday, 5 April 2014

Mockito - An Elegant Stub for a More Civilised Age

In software development, we make use of something called "stubs". These are bits of code that don't do anything at the moment, but allow us to continue coding elsewhere as if they do, replacing them later. They are also used in testing to substitute for more complex objects, and this is where "mocking" (creating "mock" objects) has been developed in object-oriented programming and test-driven development.

As an extension to the college work I've been doing, I've been looking into using mock libraries for unit testing and I've come across Mockito:

The mock objects it creates are, well, amazing to say the least. Say we've got an interface that, in turn, allows us to create a read I/O stream and a write I/O stream, for networking. The interface would look something like this:

//simple interface wrapper around a network socket
public interface MySocket {
    //creates a read I/O stream
    public BufferedReader getBufferedReader() throws IOException;
    //creates a write I/O stream
    public PrintWriter getPrintWriter() throws IOException;
    //indicates that a connection has been successfully made
    public boolean isConnected();
    //closes the connection
    public void close() throws IOException;
}

Now I can actually mock this interface with Mockito in the unit test:
import static org.mockito.Mockito.*;
...
MySocket socket = mock(MySocket.class);
You can now use this mock socket interface in whatever need the interface, so:
SocketThread socketThread = new SocketThread(socket);

Now, unfortunately, the mock doesn't really do anything other than just record what happens to it. Say SocketThread calls socket.close internally when it runs:
//this is in SocketThread.run
socket.close();
...
//if this isn't true, you'll get an exception
verify(socket).close();
Useful, but it becomes a bit more powerful when we add mocks for the input and output streams:
PrintWriter printWriter = mock(PrintWriter.class);
BufferedReader bufferedReader = mock(BufferedReader.class);
when(socket.getBufferedReader()).thenReturn(bufferedReader);
when(socket.getPrintWriter()).thenReturn(printWriter);
You can control exactly what the mock does and when it does it. Very useful for unit testing (and I haven't even begun to use all it's capabilities).

No comments:

Post a Comment