2

My goal is to simulate ServerSocket communicating with Socket. However, I can't mimic the method blocks until input data is available of InputStream.read() using mockito.

My expected result: I can simulate method block if I call dis.readByte().

My actual result: thenCallRealMethod() will throw NullPointerException or thenReturn(-1) will throw EOFException.

What I've did:

  1. Look into SocketInputStream.java source code, and I am confused how this snippet of code can simulate method block. The read(temp, 0, 1) leads to native method socketRead0, so I can't read what inside this method. If you may, it would be nice if you are willing to spend time to explain how to read the native method. I use IntelliJ IDEA and rely on this key strokes CTRL+B or CTRL+SHIFT+B to help me see the source code, in this case pressing the CTRL+B or CTRL+SHIFT+B does not lead to the .c file. CMIIW based on this reference, I concluded that native method is a method that always written in C?

I found SocketInputStream.java by following the ServerSocket.accept() method and Socket.getInputStream().

SocketInputStream.java

    /**
     * Reads a single byte from the socket.
     */
    public int read() throws IOException {
        if (eof) {
            return -1;
        }
        temp = new byte[1];
        int n = read(temp, 0, 1);
        if (n <= 0) {
            return -1;
        }
        return temp[0] & 0xff;
    }

The test using mockito.

  @Test
  public void mockTest() {
    InputStream in = mock(InputStream.class);
    DataInputStream dis = new DataInputStream(in);
    try {
      when(in.read())
              .thenReturn(0x81)
              .thenReturn(0x82)
              .thenReturn(0x89)
              .thenReturn(0x8A)
              .thenReturn(0x88);
      // thenReturn simulate method block
    } catch (IOException e) {
      e.printStackTrace();
    }

    try {
      assertEquals(dis.readByte(), (byte) 0x81);
      assertEquals(dis.readByte(), (byte) 0x82);
      assertEquals(dis.readByte(), (byte) 0x89);
      assertEquals(dis.readByte(), (byte) 0x8A);
      assertEquals(dis.readByte(), (byte) 0x88);
      logger.debug(String.valueOf(dis.readByte())); // expected not to print nor throw EOFException.
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
Jonathan
  • 1,955
  • 5
  • 30
  • 50
Jason Rich Darmawan
  • 1,607
  • 3
  • 14
  • 31
  • What you want should be possible to achieve with [`thenAnswer`](https://javadoc.io/static/org.mockito/mockito-core/3.11.2/org/mockito/Mockito.html#answer_stubs). We would set a `Thread.sleep(...)` in the body of the callable before returning a predefined value. – Turing85 Aug 15 '21 at 05:59
  • 1
    `thenAnswer(i -> { Thread.sleep(1000); return 0; });` will only delay it for 1s. if I do `fail("expected not to be executed nor throw EOFException: " + dis.readByte());`, is there any way to simulate real `method blocks until input data is available`? – Jason Rich Darmawan Aug 15 '21 at 06:28
  • Eh... `while (true) { Thread.sleep(1000); }` does the job. – Jason Rich Darmawan Aug 15 '21 at 06:29
  • 1
    If it blocks indefinitely won't your test never complete? – tgdavies Aug 15 '21 at 06:33
  • @tgdavies I will run it in a thread and check it after 2 seconds. if the thread is still alive then the test success to simulate a method block. – Jason Rich Darmawan Aug 15 '21 at 06:38
  • @user16320675 I am trying to understand how actually `Socket.getInputStream().read()` works. I want to create my own method block. I know `while (true) { Thread.sleep(100); }` is not the answer, but at least it's getting somewhere. – Jason Rich Darmawan Aug 15 '21 at 06:56
  • @user16320675 thank you for the reference. I will read it by tomorrow morning.I learnt about ServerSocket from Oracle's tutorial for the last 2 week to build the websocket server. I tried to use combination of `Object closeLock = new Object();` `synchronized(closeLock) { closeLock.wait(); }` and it throws `IllegalStateMonitorException`. I will post another SO's question after tomorrow night. I intend to use this logic `method block until input data available` for the WebSocket server listener. – Jason Rich Darmawan Aug 15 '21 at 07:17

0 Answers0