用Java模拟URL

bow*_*sie 21 java url mocking

我们在我们想要模拟的一个Java类中有一个URL对象,但它是最后一个类,所以我们不能.我们不希望达到上述水平,并模拟InputStream,因为这仍然会给我们带来未经测试的代码(我们有严格的测试覆盖标准).

我已经尝试过jMockIt的反射功能,但是我们在Mac上工作,并且Java代理处理程序存在一些我无法解决的问题.

那么在junit测试中是否有任何不涉及使用真实URL的解决方案?

Art*_*cto 20

就像Rob说的,如果你想要的是模拟从URL返回的连接,你可以扩展URLStreamHandler.例如,使用mockito:

final URLConnection mockUrlCon = mock(URLConnection.class);

ByteArrayInputStream is = new ByteArrayInputStream(
        "<myList></myList>".getBytes("UTF-8"));
doReturn(is).when(mockUrlCon).getInputStream();

//make getLastModified() return first 10, then 11
when(mockUrlCon.getLastModified()).thenReturn((Long)10L, (Long)11L);

URLStreamHandler stubUrlHandler = new URLStreamHandler() {
    @Override
     protected URLConnection openConnection(URL u) throws IOException {
        return mockUrlCon;
     }            
};
URL url = new URL("foo", "bar", 99, "/foobar", stubUrlHandler);
doReturn(url).when(mockClassloader).getResource("pseudo-xml-path");
Run Code Online (Sandbox Code Playgroud)


tva*_*son 19

当我有不容易被嘲笑,因为它是最后的(或C#密封)一类,我平时的路线是编写类周围的包装和使用包装的地方我会用实际的类.然后我会根据需要模拟包装类.

  • "非常严格的覆盖标准" - 代码覆盖率是一个负面指标,这意味着它只会在您*没有覆盖时告诉有用的信息.一旦你获得了报道,它并没有真正告诉你关于代码质量的任何信息.即,覆盖范围并不表示经过良好测试的代码.如果可以的话,我建议你尝试改变严苛的标准. (7认同)
  • 是的但是我需要单独测试包装器,里面有URL类,问题仍然存在. (2认同)

kol*_*aTM 9

我选择了以下内容:

public static URL getMockUrl(final String filename) throws IOException {
    final File file = new File("testdata/" + filename);
    assertTrue("Mock HTML File " + filename + " not found", file.exists());
    final URLConnection mockConnection = Mockito.mock(URLConnection.class);
    given(mockConnection.getInputStream()).willReturn(
            new FileInputStream(file));

    final URLStreamHandler handler = new URLStreamHandler() {

        @Override
        protected URLConnection openConnection(final URL arg0)
                throws IOException {
            return mockConnection;
        }
    };
    final URL url = new URL("http://foo.bar", "foo.bar", 80, "", handler);
    return url;
}
Run Code Online (Sandbox Code Playgroud)

这给了我一个包含我的模拟数据的真实URL对象.


Rob*_*rco 7

我使用了一个URLHandler,它允许我从类路径加载一个URL.所以以下

new URL("resource:///foo").openStream()
Run Code Online (Sandbox Code Playgroud)

将从类路径中打开一个名为foo的文件.为此,我使用一个通用的实用程序库并注册一个处理程序.要使用此处理程序,您只需要调用:

com.healthmarketscience.common.util.resource.Handler.init();
Run Code Online (Sandbox Code Playgroud)

并且资源URL现在可用.


小智 7

我认为你可以使用 Powermock 来做到这一点。我最近能够使用 PowerMock 模拟 URL 类。希望这可以帮助。

/* 实际类 */

import java.net.MalformedURLException;
import java.net.URL;

public class TestClass {

    public URL getUrl()
        throws MalformedURLException {

        URL url = new URL("http://localhost/");
        return url;
    }
}
Run Code Online (Sandbox Code Playgroud)

/* 测试类 */

import java.net.URL;

import junit.framework.Assert;

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

@RunWith(PowerMockRunner.class)
@PrepareForTest(value = { TestClass.class })
public class TestClassTest {

    private TestClass testClass = new TestClass();

    @Test
    public void shouldReturnUrl()
        throws Exception {

        URL url = PowerMockito.mock(URL.class);
        PowerMockito.whenNew(URL.class).withParameterTypes(String.class)
                .withArguments(Mockito.anyString()).thenReturn(url);
        URL url1 = testClass.getUrl();
        Assert.assertNotNull(url1);
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 6

如果您不想创建包装器:

注册一个URLStreamHandlerFactory

公开您想要的方法

模拟链

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

PS:我不知道如何在最后一行之后取消编号列表的自动间隔

  • 根据您的回答,我写了以下博客文章:https://claritysoftware.co.uk/mocking-javas-url-with-mockito/ (2认同)