0

I have a piece of code I'd like to test -

 ServerHello connect(
        int version, Collection<Integer> cipherSuites)
    {
        Socket s = null;
        try {

            if(proxy!=null) {
                s = new Socket(proxy);
            }else {
                s = new Socket();
            }
            try {
                s.connect(isa);

            } catch (IOException ioe) {
                System.err.println("could not connect to "
                    + isa + ": " + ioe.toString());
                return null;
            }
            byte[] ch = makeClientHello(version, cipherSuites);
            OutputRecord orec = new OutputRecord(
                s.getOutputStream());
            orec.setType(Constants.HANDSHAKE);
            orec.setVersion(version);
            orec.write(ch);
            orec.flush();
            ServerHello x = new ServerHello(s.getInputStream());
            return x;
        } catch (IOException ioe) {
        } finally {
            try {
                s.close();
            } catch (IOException ioe) {
                // ignored
            }
        }
        return null;
    }

I want to mock this.socket.getInputStream() and this.socket.getOutputStream() data with my own. How do I set this data?

And also, I want o make sure that this.socket.connect() passes in any test without throwing any exceptions in my tests (offline tests).

How do I do it ? I'm using Mockito framework for tests

Prateek Narendra
  • 1,837
  • 5
  • 38
  • 67

1 Answers1

4

Its rather easy, you simply need to mock your socket and route your mock-method in such a way that it returns your own stream and capture the written data :

@RunWith(MockitoJUnitRunner.class)
public class MyTest
{
   @Mock
   private Socket socket;

   @Mock
   private OutputStream myOutputStream;

   @Captor
   private ArgumentCaptor<byte[]> valueCapture;

   @Test
   public void test01()
   {
     Mockito.when(socket.getOutputStream()).thenReturn(myOutputStream);

     //EXECUTE YOUR TEST LOGIC HERE

     Mockito.verify(myOutputStream).write(valueCapture.capture());
     byte[] writtenData = valueCapture.getValue();        
   }

}

I recommend doing some sort of tutorial, for example : https://www.baeldung.com/mockito-annotations or maybe https://examples.javacodegeeks.com/core-java/mockito/mockito-tutorial-beginners/

specializt
  • 1,913
  • 15
  • 26
  • The doubt is how exactly do I create my own OutputStream object with some data? And How do I prevent socket.connect from throwing an error? – Prateek Narendra Mar 22 '19 at 07:05
  • you can also mock your stream and have it return fixed byte-arrays, for instance - in the same way as described above. Mocks will never throw errors, by default each method will return null. If you dont want them to return null you either need to route your mock methods or you can simply have them call "real" methods : `@Mock(answer=Answers.CALLS_REAL_METHODS)` but in that case you're not writing a proper unit test anymore ... thats already integration testing – specializt Mar 22 '19 at 07:06
  • Can you show me an example where you set the data with your own byte array ? – Prateek Narendra Mar 22 '19 at 07:08
  • I just need to ensure that socket.connect() doesnt throw an exception. And then mock the data returned when you call socket.getOutputStream and socket.getInputStream – Prateek Narendra Mar 22 '19 at 07:15
  • `socket.connect()` can not throw an exception since it is mocked. Maybe your code does call the method and expect something specific to happen. Please read the documentation pointed to above on how mocks work. If you use mocks you need to tell them what to do. – cmoetzing Mar 22 '19 at 07:24
  • see my edit, it now captures data which is written to your mocked stream – specializt Mar 22 '19 at 07:29
  • @specializt I realized that once socket is closed, I cannot reopen again. How do I have control of the new Socket object created in the method and then mock it? I have changed the code block – Prateek Narendra Mar 22 '19 at 07:48
  • You obviously do not know how testing works ... never use real sockets in your tests in the beginning ... also : never test more than one single "unit" per test - for example a class. You **really** need to read something like this : https://www.vogella.com/tutorials/JUnit/article.html and this : https://stackoverflow.com/a/652382/351861 – specializt Mar 22 '19 at 07:54
  • 1
    also : read my example, it clearly shows how to test a socket properly **and** capture data passed into it – specializt Mar 22 '19 at 08:01