Mockito with JUnit

When you write/used to write test cases for your newly added function in your program, you may have come to the point where you realize the input for this function depends on the output of another  program or system or resources, like http, database call etc. and we can not make the call because it is for tests. right? Calling real resources does not make sense either, or will you maintain all of these just to pass the tests you have written? Obviously not.

Here comes Mockito handy, with Mockito you can mock all most everything, and write codes to return object you wanted to.

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>4.5.1</version>
<scope>test</scope>
</dependency>

Lets go through example to understand its working better.

Lets say, I have a socket echo server and client. The server echoes back everything client writes. And at client side you have to verify without making any call to the server. So how will you write your client side code?

The answer is you can mock the streams that you obtained with socket. Whenever you write to the socket, you use its output stream, we can use that.

  1. EchoClient.java
    package test;

    import java.io.IOException;
    import java.net.Socket;

    public class EchoClient {

    final Socket socket;

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

    public byte[] echo(byte[] message) throws IOException {
    socket.getOutputStream().write(message);
    byte[] messageRead = new byte[message.length];
    int read = socket.getInputStream().read(messageRead);
    if (read == -1) {
    throw new IOException("no data read.");
    }
    return messageRead;
    }
    }
  2. EchoClientTest.java
    package test;

    import org.junit.jupiter.api.Assertions;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.mockito.Mock;
    import org.mockito.Mockito;
    import org.mockito.junit.jupiter.MockitoExtension;

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
    import java.nio.charset.StandardCharsets;

    import static org.mockito.ArgumentMatchers.any;
    import static org.mockito.ArgumentMatchers.eq;

    @ExtendWith(MockitoExtension.class)
    public class EchoClientTest {

    @Mock Socket socket;
    // this is same as: socket = Mockito.Mock(Socket.class)

    @Mock InputStream inputStream;

    @Mock OutputStream outputStream;

    @Test
    public void testEcho() throws IOException {
    Mockito.when(socket.getInputStream()).thenReturn(inputStream);
    Mockito.when(socket.getOutputStream()).thenReturn(outputStream);

    byte[] message = "Hi".getBytes(StandardCharsets.UTF_8);
    // this is to validate write
    Mockito.doAnswer(
    (invocationOnMock) -> {
    byte[] param = invocationOnMock.getArgument(0);
    Assertions.assertArrayEquals(message, param);
    return null;
    })
    .when(outputStream)
    .write(any(byte[].class));

    // this is to validate read
    Mockito.doAnswer(
    (invocationOnMock) -> {
    byte[] param = invocationOnMock.getArgument(0);
    Assertions.assertEquals(message.length, param.length);
    // copy the message
    System.arraycopy(message, 0, param, 0, message.length);
    return message.length;
    })
    .when(inputStream)
    .read(any(byte[].class));

    EchoClient echoClient = new EchoClient(socket);
    byte[] received = echoClient.echo(message);

    // this validates echo
    Assertions.assertArrayEquals(message, received);

    // also with this approach
    // you will have to validate the outputstream and inputsteam were in use
    Mockito.verify(outputStream, Mockito.times(1)).write(any(byte[].class));
    Mockito.verify(inputStream, Mockito.times(1)).read(any(byte[].class));
    }
    }

Comments

Popular Posts