Question

I have a such method:

public boolean isFree(LdapPort port) {
    boolean result = false;
    try{
        ServerSocket ss = new ServerSocket(port.getPortNumber());
        ss.getLocalPort();
        ss.close();
    } catch(IOException ex){
        result = true;
    }
    return result;
}

The problem is, that getLocalPort() operates on real system ports and during testing it passes depending on the local system.

What should be the valid way to test such method?

Was it helpful?

Solution

The ServerSocket instance should be available via factory, which (factory) is passed as a dependency to your class:

// Passing factory dependency via constructor injection
public PortChecker(IServerSocketFactory socketFactory)
{
    this.socketFactory = socketFactory;
}

// ...
ServerSocket ss = this.socketFactory.GetServerSocket(port.getPortNumber());
ss.getLocalPort();
ss.close();

Then, in your unit test you can mock socketFactory to return fake server socket and as a result "disconnect" it from any real world systems.

Note that ServerSocket might also need to be abstraction (say, represented by interface/base class) so it can be mocked too.

OTHER TIPS

Using PowerMock you can mock constructors, details. So all the calls to the matching constructor of the class you want to mock can return a mock instance that you will prepare in your test.

Your test will require these annotations:

@RunWith(PowerMockRunner.class)
@PrepareForTest( ServerSocket.class )

Then inside the test method:

ServerSocket ssMock = createMock(ServerSocket.class);

expectNew(ServerSocket.class, port.getPortNumber()).andReturn(ssMock); // so constructor of the ServerSocket class taking this specific port number will return the ssMock instance

expect(ssMock.getLocalPort()).andReturn(10); // when method getLocalPort is invoked return 10

reply(ssMock, ServerSocket.class); // do not forget to specify not only the mock instance (ssMock) but the ServerSocket class as well

You need to look into mocking out the serverSocket class.

With your current code the new invocation makes testing hard.

Inject an instance of serversocket into you method/class you can then inject a mock instance for testing

I have always found mockito a good mocking framework

You can write

public boolean isFree(LdapPort port) {
    try{
        new ServerSocket(port.getPortNumber()).close();
        return true;
    } catch(IOException ex){
        return false;
    }
}

And you can test it by creating a ServerSocket on the same port and isFree should be false, then close the ServerSocket and isFree should be true.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top