简体   繁体   中英

Mock final classes and its method to throw exceptions

I have a final class which tries to connect to a provided URL using openConnection() . I mocked it to have it return an UnknownHostException because I know that the provided URL is unknown and to also reduce the time of the unit test (> 0.01 sec is too long for this one test).

Class to be tested:

public final class Server {
    private Server() {}

    public static void getServerStuff(final URL url) throws IOException {
        try {
            final URLConn urlConn;
            // immediately throw exception without trying to make a connection
            urlConn = url.openConnection(); 
        }
        catch (Exception e) {
            // not relevant
        }
    }
}

Unit test

public class ServerTest {

    public class UrlWrapper {

        Url url;

        public UrlWrapper(String spec) throws MalformedURLException {
        url = new URL(spec);
        }

        public URLConnection openConnection() throws IOException {
          return url.openConnection();
        }
    }

    public void testUnknownHostExceptionIsThrown() throws IOException {

        UrlWrapper mockUrl = mock(UrlWrapper.class);
        URLConnection mockUrlConn = mock(URLConnection.class);

        when(mockUrl.openConnection()).thenThrow(UnknownHostException.class);

        final String server = "blabla";
        final URL url = new URL("http://" + server);
        mockUrl.url = url;

        try {
            Server.getServerStuff(mockUrl.url);
        }
        catch (IOException e) {
            // do stuff with Assert
        }
    }
}

I am required to use mockito instead of powermockito which can mock final classes. My main problem is that I do not know how to tell the unit test to use my mocked openConnection() . It should still test my getServerStuff() method but throw the exception without actually trying to connect.

What do I need to change to make it work?

EDIT: I do not think it is a duplicate of the referenced question because I know how to mock a final class (using a wrapper, eg). My problem is the next step, meaning how to use my mocked method. My unit test will go into the to-be tested method and use the openConnection() from standard lib but I want it to use my mocked one to reduce time needed for this unit test to complete.

What is purpose of UrlWrapper when you are passing the wrapped URL object to Server ?

I am going on the assumption that you can edit Server .

Personally I would create a new interface that gets passed to your Server#getServerStuff(..) method. You can then mock the interface to provide the mocked behaviour that you desire.

public interface ServerRemote {
    public InputStream getInput() throws IOException
}

public class URLServerRemote implements ServerRemote {

    private URL url;

    public URLServerRemote(URL url) {
        this.url = url;
    }

    public InputStream getInputStream() throws IOException {
        return url.openConnection().getInputStream();
    }
}

public final class Server {
    private Server() {}

    public static void getServerStuff(final ServerRemote remote) throws IOException {
        try {
            final InputStream input;
            // immediately throw exception without trying to make a connection
            input = remote.getInputStream();
        }
        catch (Exception e) {
            // not relevant
        }
    }
}

...

public void testUnknownHostExceptionIsThrown() throws IOException {

    ServerRemote mockServerRemote = mock(ServerRemote.class);
    when(mockServerRemote.getInputStream()).thenThrow(UnknownHostException.class);

    try {
        Server.getServerStuff(mockServerRemote);
    }
    catch (IOException e) {
        // do stuff with Assert
    }
}

...

If you can not change your Server class then you are going to be stuck unless you use PowerMock.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM