Mocking a URL in Java

2020-02-23 06:38发布

We have a URL object in one of our Java classes that we want to mock, but it's a final class so we cannot. We do not want to go a level above, and mock the InputStream because that will still leave us with untested code (we have draconian test coverage standards).

I've tried jMockIt's reflective powers but we work on Macs and there are problems with the Java agent handler that I haven't been able to resolve.

So are there any solutions that do not involve using real URLs in the junit test?

标签: java url mocking
10条回答
ゆ 、 Hurt°
2楼-- · 2020-02-23 06:56

Create a URL-object pointing to the test class itself.

final URL url = 
    new URL("file://" + getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
查看更多
够拽才男人
3楼-- · 2020-02-23 06:59

If you don't want to create a wrapper :

Register a URLStreamHandlerFactory

Make the method you want public

Mock the chain

abstract public class AbstractPublicStreamHandler extends URLStreamHandler {
    @Override
    public URLConnection openConnection(URL url) throws IOException {
        return null;
    }
}

public class UrlTest {
    private URLStreamHandlerFactory urlStreamHandlerFactory;

    @Before
    public void setUp() throws Exception {
        urlStreamHandlerFactory = Mockito.mock(URLStreamHandlerFactory.class);
        URL.setURLStreamHandlerFactory(urlStreamHandlerFactory);
    }

    @Test
    public void should_return_mocked_url() throws Exception {
        // GIVEN
        AbstractPublicStreamHandler publicStreamHandler = Mockito.mock(AbstractPublicStreamHandler.class);
        Mockito.doReturn(publicStreamHandler).when(urlStreamHandlerFactory).createURLStreamHandler(Matchers.eq("http"));

        URLConnection mockedConnection = Mockito.mock(URLConnection.class);
        Mockito.doReturn(mockedConnection).when(publicStreamHandler).openConnection(Matchers.any(URL.class));

        Mockito.doReturn(new ByteArrayInputStream("hello".getBytes("UTF-8"))).when(mockedConnection).getInputStream();

        // WHEN
        URLConnection connection = new URL("http://localhost/").openConnection();

        // THEN
        Assertions.assertThat(new MockUtil().isMock(connection)).isTrue();
        Assertions.assertThat(IOUtils.toString(connection.getInputStream(), "UTF-8")).isEqualTo("hello");
    }
}

PS : I don't know how to cancel the numbered list auto-spacing after last line

查看更多
萌系小妹纸
4楼-- · 2020-02-23 07:03

I have used a URLHandler that allows me to load a URL from the classpath. So the following

new URL("resource:///foo").openStream()

would open a file named foo from within the class path. To do this, I use a common utility library and register a handler. To use this handler, you just need to call:

com.healthmarketscience.common.util.resource.Handler.init();

and the resource URL is now available.

查看更多
Juvenile、少年°
5楼-- · 2020-02-23 07:10

Does the URL class implement an interface? If so then you could instantiate it using inversion of control or a configurable factory, rather than by direct construction, this would allow you to inject/construct a test instance at test runtime rather than the final instance you currently have.

查看更多
登录 后发表回答