Java 如何模拟URL连接

Java 如何模拟URL连接,java,junit,mocking,powermock,jmockit,Java,Junit,Mocking,Powermock,Jmockit,嗨,我有一个方法,它将URL作为输入,并确定它是否可访问。 下面是代码: public static boolean isUrlAccessible(final String urlToValidate) throws WAGNetworkException { URL url = null; HttpURLConnection huc = null; int responseCode = -1; try {

嗨,我有一个方法,它将URL作为输入,并确定它是否可访问。 下面是代码:

public static boolean isUrlAccessible(final String urlToValidate) throws WAGNetworkException {
        URL url = null;
        HttpURLConnection huc = null;
        int responseCode = -1;
        try {
            url = new URL(urlToValidate);
            huc = (HttpURLConnection) url.openConnection();
            huc.setRequestMethod("HEAD");
            huc.connect();
            responseCode = huc.getResponseCode();
        } catch (final UnknownHostException e) {
            throw new WAGNetworkException(WAGConstants.INTERNET_CONNECTION_EXCEPTION);
        } catch (IOException e) {
            throw new WAGNetworkException(WAGConstants.INVALID_URL_EXCEPTION);
        } finally {
            if (huc != null) {
                huc.disconnect();
            }
        }
        return responseCode == 200;
    }

我想使用
PowerMockito
对isurlacables()方法进行单元测试。我觉得我需要使用
whenNew()
来模拟
URL
的创建,当调用
URL.openConnection()
时,返回另一个模拟
HttpURLConnection
对象。但我不知道如何实施这一点?我走对了吗?有人能帮我实现这个吗?

你可以用

whenNew(URL.class)..
确保从该whenNew调用返回先前创建的模拟对象

URL mockUrl = Mockito.mock(URL.class);
whenNew(URL.class).....thenReturn(mockUrl );

然后,您可以根据需要将行为添加到模拟中。

找到了解决方案。首先模拟URL类,然后模拟HttpURLConnection,当调用URL.openconnection()时,返回这个模拟的HttpURLConnection对象,最后将其响应代码设置为200。代码如下:

@Test
    public void function() throws Exception{
        RuleEngineUtil r = new RuleEngineUtil();
        URL u = PowerMockito.mock(URL.class);
        String url = "http://www.sdsgle.com";
        PowerMockito.whenNew(URL.class).withArguments(url).thenReturn(u);
        HttpURLConnection huc = PowerMockito.mock(HttpURLConnection.class);
        PowerMockito.when(u.openConnection()).thenReturn(huc);
        PowerMockito.when(huc.getResponseCode()).thenReturn(200);
        assertTrue(r.isUrlAccessible(url));

    }

为了通过
mockito
库模拟java.net.URL类,您需要执行以下步骤:

  • 在src/tests/resources目录中创建一个名为“mockitoextensions”的目录
  • 在名为org.mockito.plugins.MockMaker的文件夹中创建文本文件,并将
    mock maker内联
    text放入该文件
  • 您可以按如下方式模拟该类:
代码:

package myproject;

import org.junit.Test;

import java.net.HttpURLConnection;
import java.net.URL;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

public class Test {
    @Test
    public void test() throws Exception {
        URL url = mock(URL.class);
        HttpURLConnection huc = mock(HttpURLConnection.class);
        when(url.openConnection()).thenReturn(huc);
        assertTrue(url.openConnection() instanceof HttpURLConnection);
    }
}

URL是最后一个类。为了模拟最后一个类,我们可以将PowerMockito与Junit一起使用。 为了模拟最后一个类,我们需要用@RunWith(PowerMockRunner.class)和@PrepareForTest({URL.class})注释测试类

但是在行PowerMockito.when(url.openConnection()).thenReturn(huc)引发以下错误:

java.lang.AbstractMethodError
    at java.net.URL.openConnection(URL.java:971)
    at java_net_URL$openConnection.call(Unknown Source) 
为了消除此错误,我们可以修改我们的测试类,如下所示:

@RunWith(PowerMockRunner.class) 
@PrepareForTest({ URL.class })
public class Test {
    @Test
    public void test() throws Exception {

        public class UrlWrapper {

            URL url;

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

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

        UrlWrapper url = Mockito.mock(UrlWrapper.class);
        HttpURLConnection huc = Mockito.mock(HttpURLConnection.class);
        PowerMockito.when(url.openConnection()).thenReturn(huc);
        assertTrue(url.openConnection() instanceof HttpURLConnection);
    }
}

访问:

使用JMockit模拟API要简单得多(没有模拟更简单):


(在JDKs 8和9上使用JMockit 1.47进行了验证。)

尽管此线程有一些好的建议,但如果您中的任何人对使用这些第三方库不感兴趣,这里有一个快速的解决方案

public class MockHttpURLConnection extends HttpURLConnection {
    private int responseCode;
    private URL url;
    private InputStream inputStream;


    public MockHttpURLConnection(URL u){
        super(null);
        this.url=u;
    }
    @Override
    public int getResponseCode() {
        return responseCode;
    }


    public void setResponseCode(int responseCode) {
        this.responseCode = responseCode;
    }

    @Override
    public URL getURL() {
        return url;
    }

    public void setUrl(URL url) {
        this.url = url;
    }

    @Override
    public InputStream getInputStream() {
        return inputStream;
    }

    public void setInputStream(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    @Override
    public void disconnect() {

    }

    @Override
    public boolean usingProxy() {
        return false;
    }

    @Override
    public void connect() throws IOException {

    }
}
这就是如何设置所需的行为

   MockHttpURLConnection httpURLConnection=new MockHttpURLConnection(new URL("my_fancy_url"));
        InputStream stream=new ByteArrayInputStream(json_response.getBytes());
        httpURLConnection.setInputStream(stream);
        httpURLConnection.setResponseCode(200);

注意:它只模拟了
HttpUrlConnection
中的3个方法,如果要使用更多方法,则需要确保这些方法也是模拟的

不管它值多少钱,我建议您仔细研究一下JMockit(JMockit.github.io),然后看看您是否可以放弃它——我不能,而且从那以后它一直是我的模拟框架。这是否有效,它在第
PowerMockito.when(u.openConnection())行给我一个错误。然后返回(huc),说AbstractMethodError.com对我也不起作用。。。我得到:java.NET.MalFrimeUrLeExpRe:没有嘲讽URL的协议,你也应该考虑添加@ PravaReFielt({ URL.class,}),因为我们不能模拟最后一个类(URL)@ DON,Powermockito可以模拟最后一个类(URL)。
public class MockHttpURLConnection extends HttpURLConnection {
    private int responseCode;
    private URL url;
    private InputStream inputStream;


    public MockHttpURLConnection(URL u){
        super(null);
        this.url=u;
    }
    @Override
    public int getResponseCode() {
        return responseCode;
    }


    public void setResponseCode(int responseCode) {
        this.responseCode = responseCode;
    }

    @Override
    public URL getURL() {
        return url;
    }

    public void setUrl(URL url) {
        this.url = url;
    }

    @Override
    public InputStream getInputStream() {
        return inputStream;
    }

    public void setInputStream(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    @Override
    public void disconnect() {

    }

    @Override
    public boolean usingProxy() {
        return false;
    }

    @Override
    public void connect() throws IOException {

    }
}
   MockHttpURLConnection httpURLConnection=new MockHttpURLConnection(new URL("my_fancy_url"));
        InputStream stream=new ByteArrayInputStream(json_response.getBytes());
        httpURLConnection.setInputStream(stream);
        httpURLConnection.setResponseCode(200);