Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中模拟URL_Java_Url_Mocking - Fatal编程技术网

在Java中模拟URL

在Java中模拟URL,java,url,mocking,Java,Url,Mocking,我们想模拟其中一个Java类中的URL对象,但它是最后一个类,所以我们不能。我们不想达到更高的级别,并模拟InputStream,因为这仍然会留下未经测试的代码(我们有严格的测试覆盖率标准) 我尝试过jMockIt的反射功能,但我们在Mac上工作,Java代理处理程序存在一些问题,我还没有解决 那么,有什么解决方案不涉及在junit测试中使用真实URL吗?当我有一个类,因为它是最终的(或用C#密封),所以不容易被模仿时,我通常的方法是围绕该类编写一个包装器,并在我使用实际类的任何地方使用该包装器

我们想模拟其中一个Java类中的URL对象,但它是最后一个类,所以我们不能。我们不想达到更高的级别,并模拟InputStream,因为这仍然会留下未经测试的代码(我们有严格的测试覆盖率标准)

我尝试过jMockIt的反射功能,但我们在Mac上工作,Java代理处理程序存在一些问题,我还没有解决


那么,有什么解决方案不涉及在junit测试中使用真实URL吗?

当我有一个类,因为它是最终的(或用C#密封),所以不容易被模仿时,我通常的方法是围绕该类编写一个包装器,并在我使用实际类的任何地方使用该包装器。然后根据需要模拟包装器类。

我使用了一个URLHandler,它允许我从类路径加载URL。那么下面

new URL("resource:///foo").openStream()
将从类路径中打开名为foo的文件。要做到这一点,我使用一个函数并注册一个处理程序。要使用此处理程序,只需调用:

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

资源URL现在可用。

我将再次了解您为什么要模拟最终的数据对象。因为根据定义,您在实际代码中没有对对象进行子类化,而且它也不会是被测试的对象,所以您不需要对该代码进行白盒测试;只要传入任何合适的(真实的)URL对象,并检查输出


当很难创建合适的真实对象,或者真实对象的方法很耗时或者依赖于某个有状态的外部资源(如数据库)时,模拟对象非常有用。这两种方法都不适用于本例,因此我不明白为什么不能构造一个表示适当资源位置的真实URL对象。

URL类实现接口了吗?如果是这样,那么您可以使用控制反转或可配置工厂来实例化它,而不是直接构造,这将允许您在测试运行时注入/构造测试实例,而不是当前拥有的最终实例。

JMockit确实允许您模拟最终的JRE类,如java.net.URL

除了Sun之外,JDK1.6实现中的jdkDir/lib/tools.jar中的Attach API似乎也不起作用。我猜这些东西还是太新/太高级了,或者根本没有得到其他JDK供应商(苹果、IBM和J9JDK、Oracle和JRockit JDK)的必要关注


因此,如果您在类路径中使用tools.jar时遇到问题,请尝试使用“-javaagent:jmockit.jar”JVM参数。它告诉JVM在启动时直接加载java代理,而不使用附加API。这应该在Apple JDK 1.5/1.6中起作用。

正如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");
final URLConnection mockUrlCon=mock(URLConnection.class);
ByteArrayInputStream是=新的ByteArrayInputStream(
.getBytes(“UTF-8”);
doReturn(is).when(mockUrlCon).getInputStream();
//使getLastModified()先返回10,然后返回11
当(mockUrlCon.getLastModified())。然后返回((长)10L,(长)11L);
URLStreamHandler stubUrlHandler=新的URLStreamHandler(){
@凌驾
受保护的URL连接openConnection(URL u)引发IOException{
返回mockUrlCon;
}            
};
URL URL=新URL(“foo”、“bar”、99、/foobar”、stubUrlHandler);
doReturn(url).when(mockClassloader).getResource(“伪xml路径”);

我同意以下观点:

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;
}

这为我提供了一个包含模拟数据的真实URL对象。

我认为您可以使用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;
    }
}
/*测试班*/

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);
    }
}

如果不想创建包装,请执行以下操作:

注册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");
    }
}

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

创建一个指向测试类本身的URL对象

final URL url = 
    new URL("file://" + getClass().getProtectionDomain().getCodeSource().getLocation().getPath());

是的,但是我需要对包装器进行单元测试,并在其中包含URL类,问题仍然存在。否。包装器非常薄,只反映URL上的方法。你不需要对它进行单元测试,你应该能够通过检查来验证它。嗯,是的,这是真的。正如我上面所说的,这是因为我们有非常严格的覆盖标准,我需要从我们的覆盖范围中去掉包装。但这是我们最初提出的解决方案,我想这是有道理的。谢谢“相当严格的覆盖率标准”-代码覆盖率是一个负指标,这意味着它只在你没有覆盖率的情况下告诉你有用的信息。一旦获得覆盖率,它就不会真正告诉您关于代码质量的任何信息。也就是说,覆盖范围并不表示代码经过良好测试。如果可以的话,我建议你尝试改变严格的标准。这被标记为一个公认的答案,有没有一个例子说明你是如何编写包装并测试包装而不是
新URL
?当然,这是希望将测试与任何类型的真实URL分离,当我们调用openConnection时,我们打开了一个新的依赖项。我认为这是一个合法的问题。模拟框架不应该隐藏这些东西……不,正如我上面所说,URL是最后一个类,它来自JDK。好的,我把问题理解为“我们有一个由最后一个类实现的URL对象(比如MyURL,据我所知,它可能有一个接口)我们没有java.net.URL类本身的实例。我认为这个问题可能会更明确一些。当然,它可能会更明确一些,但它是否是自定义URL有点含糊不清,抱歉-但它仍然说它是最终的,所以…有些东西可能是最终的,仍然实现了一个接口,将自己借给工厂或者注射施工。我把这个加上1,它不应该是-1,因为你可以创建一个工厂来做和你一样的事情