Home > database >  How can we write test cases for Socket connections
How can we write test cases for Socket connections

Time:12-23

Below is the code snippet for which the Socket connection has to be tested for true and false scenarios.

public boolean pingHost(String hostname, int port) {
    try (Socket socket = new Socket()) {
        socket.connect(new InetSocketAddress(hostname, port), 3000);
        return true;
    } catch (IOException e) {
        return false;
    }
}

CodePudding user response:

This is a standard use case for mocking. With PowerMock i.e. you can mock constructor calls and return a mock object. Also you can verify the correct parameter in the constructor call. Just search for 'Powermock mocking constructor'. If mocking is not an option to you, an alterative could be to listen on a port using netcat which is available for *NIX and Windows platform.

EDIT 2021.12.16 -----------------

You need to include these four jars to have Mockito and PowerMock available (Maven pom)

    <!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>4.1.0</version>
        <scope>test</scope>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.mockito/mockito-inline -->
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-inline</artifactId>
        <version>4.1.0</version>
        <scope>test</scope>
    </dependency>

    <!-- https://www.baeldung.com/intro-to-powermock -->
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>2.0.9</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-api-mockito2</artifactId>
        <version>2.0.9</version>
        <scope>test</scope>
    </dependency>

But there is a lot of documentation available on how to setup Mockito and PowerMock.

Here's a runnable example with some annotations to give you a glimpse of how to test with mocks.

package __scratchpad__;

import static org.junit.Assert.fail;
import static org.powermock.api.mockito.PowerMockito.whenNew;

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

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;



@RunWith(PowerMockRunner.class)
@PrepareForTest(PingerTest.Pinger.class)
public class PingerTest {

    
    // Inner class just to have a compact 'all in one' example
    public class Pinger {
        
        // refactored to better coding style (avoid 'Magic numbers') 
        // AND for testability because TIM-OUT is now accessible for test
        public static final int TIME_OUT = 3000;

        public boolean pingHost(String hostname, int port) {
            
            try (Socket socket = new Socket()){
                socket.connect(new InetSocketAddress(hostname, port), TIME_OUT);
                return true;
            } catch (IOException e) {
                return false;
            }
        }
        
    }
    

    @Test
    public void testPingHost() {
        
        // create required mock objects to inject 
        InetSocketAddress addressMock = Mockito.mock(InetSocketAddress.class);
        Socket socketMock = Mockito.mock(Socket.class);
        
        // create parameters 
        final String hostname = "answer.deepthought";
        final int port = 42;
        final int timeOut = PingerTest.Pinger.TIME_OUT;
        
        // create class under test
        Pinger pingerUnderTest = new Pinger();
        
        try {
            
            // mock constructor call of class InetSocketAddress and verify correct parameters
            // If parameters of call are different to the expected, than NO mock object is returned, the test will fail
            // Otherwise the addressMock object is returned
            whenNew(InetSocketAddress.class)
              .withArguments(hostname, port)
              .thenReturn(addressMock);
            
            // mock constructor call of Socket class
            whenNew(Socket.class)
              .withNoArguments()
              .thenReturn(socketMock);
            
            // call method under test with parameters defined earlier.
            // If parameters are different to them of InetSocketAddress constructor call the test will fail.
            pingerUnderTest.pingHost(hostname, port);
            
            // if all works fine exactly one call to method connect() with specified parameters MUST appear
            // if there are more or less calls or any of the parameters is different, than the test will fail
            Mockito.verify(socketMock).connect(addressMock, timeOut);
            
        } catch(Exception e) {
            e.printStackTrace();
            fail("Unexpected exception caught!");
        }
        
    }

}
  • Related