Tuesday, December 07, 2010

Mockito: verify order of invocations

Sometimes there is need to verify the order of invocations happened on mock object. Take a look at below RequestProcessor class. This class reads request from input stream, does some processing, write response to output stream and closes the connection.

public class RequestProcessor {
    private Socket socket;

    public RequestProcessor(Socket socket) {
        this.socket = socket;
    }

    public void process() {
        try {
            InputStream is = socket.getInputStream();
            String response = processRequest(is);

            PrintWriter pw = new PrintWriter(socket.getOutputStream());
            pw.append(response);
            pw.flush();
        } catch (IOException e) {
            // catch exception
        } finally {
            try {
                socket.close();
            } catch (IOException e) {}
        }
    }
  
    private String processRequest(InputStream is) {
        // process request and send response
    }
}

Here, we want to verify that in ideal case RequestProcessor should first read request from socket.getInputStream() and then after processing request, write response in socket.getOutputStream(). One way that comes in mind is to write test as:

@Test public void socketClosedInIdealCase() throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ByteArrayInputStream bais = new ByteArrayInputStream("a=b+c".getBytes());
  
    when(socketMock.getInputStream()).thenReturn(bais);
    when(socketMock.getOutputStream()).thenReturn(baos);

    RequestProcessor request = new RequestProcessor(socketMock);  
    request.process();

    // verify method invocations
    verify(socketMock).getInputStream();
    verify(socketMock).getOutputStream();  
}

At first this test seems to be verifying what is suppose to, but unfortunately this test will not detect if socket.getOutputStream() is moved before socket.getInputStream() as done in below code.

public void process() {
    try {
        OutputStream os = socket.getOutputStream()
        InputStream is = socket.getInputStream();
        String response = processRequest(is);
 
        // rest of the code
        } catch (IOException e) {
            // catch exception
        } finally {
            try {
                socket.close();
            } catch (IOException e) {}
        }
    }
}

This is because Mockito.verify() static method only verifies whether any invocation happened on mock object. It does not verifies order of invocation.

To make test verify invocation order, Mockito provides Mockito.inOrder static method. Using this method above test can be rewritten as:

@Test public void socketClosedInIdealCase() throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ByteArrayInputStream bais = new ByteArrayInputStream("a=b+c".getBytes());
  
    when(socketMock.getInputStream()).thenReturn(bais);
    when(socketMock.getOutputStream()).thenReturn(baos);

    RequestProcessor request = new RequestProcessor(socketMock);  
    request.process();

    // verify method invocations
    InOrder order = inOrder(socketMock);
    order.verify(socketMock).getInputStream();
    order.verify(socketMock).getOutputStream();
}

If the order of invocation is changed in RequestProcessor.process() method, this test will fail.

Below is complete code.



No comments:

Post a Comment