Java 如何模拟 URL 连接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25334139/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 00:07:36  来源:igfitidea点击:

how to mock a URL connection

javajunitmockingpowermockjmockit

提问by Nemin

Hi I have a method that takes an URL as an input and determines if it is reachable. Heres the code for that:

嗨,我有一种方法可以将 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;
    }

I want to unit test the isUrlAccessible() method using PowerMockito. I feel that I will need to use whenNew()to mock the creation of URLand the when url.openConnection()is called, return another mock HttpURLConnectionobject. But I have am not sure how to implement this? Am I on the right track? Can anyone help me in implementing this?

我想使用PowerMockito. 我觉得我将需要使用whenNew()来模拟的创建URLurl.openConnection()调用时,返回另一个模拟HttpURLConnection对象。但我不确定如何实现这一点?我在正确的轨道上吗?任何人都可以帮助我实现这一点吗?

采纳答案by Nemin

Found the solution. First mock the URL class, then Mock the HttpURLConnection and when url.openconnection() is called, return this mocked HttpURLConnection object and finally set its response code to 200. Heres the code:

找到了解决办法。首先模拟 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));

    }

回答by Sezin Karli

You can mock new Url instance with

您可以模拟新的 Url 实例

whenNew(URL.class)..

Make sure you return a previously created mock object from that whenNew call.

确保从 whenNew 调用中返回先前创建的模拟对象。

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

Then you can add behavior to your mock as you want.

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

回答by ?brahim Gündüz

In order to mock java.net.URL class through mockitolibrary, you need to perform the following steps:

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

  • Create a directory, named 'mockito-extensions' in src/tests/resources directory.
  • Create text a text file in the folder, named org.mockito.plugins.MockMaker and put mock-maker-inlinetext into the file.
  • you can mock the class like the following:
  • 在 src/tests/resources 目录中创建一个名为“mockito-extensions”的目录。
  • 在文件夹中创建一个文本文件,命名为 org.mockito.plugins.MockMaker 并将mock-maker-inline文本放入文件中。
  • 你可以像下面这样模拟这个类:

code:

代码:

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

回答by Pranab Thakuria

URL is final class. To mock final class we can use PowerMockito with Junit. To mock final class we need to annotate Test class with @RunWith(PowerMockRunner.class) and @PrepareForTest({ URL.class })

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


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

But in the line PowerMockito.when(url.openConnection()).thenReturn(huc);following error is thrown:

但是在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) 

In order to get rid of this error we can modify our Test class as shown below:

为了摆脱这个错误,我们可以修改我们的 Test 类,如下所示:

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

Visit: https://programmingproblemsandsolutions.blogspot.com/2019/04/abstractmethoderror-is-thrown-on.html

访问:https: //programmingproblemsandsolutions.blogspot.com/2019/04/abstractmethoderror-is-thrown-on.html

回答by Rogério

It's much simpler with the JMockit mocking API (and even simpler with no mocking):

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

import java.io.*;
import java.net.*;
import org.junit.*;
import static org.junit.Assert.*;
import mockit.*;

public final class ExampleURLTest {
   public static final class ClassUnderTest {
      public static boolean isUrlAccessible(String urlToValidate) throws IOException {
         HttpURLConnection huc = null;
         int responseCode;

         try {
            URL url = new URL(urlToValidate);
            huc = (HttpURLConnection) url.openConnection();
            huc.setRequestMethod("HEAD");
            huc.connect();
            responseCode = huc.getResponseCode();
         }
         finally {
            if (huc != null) {
               huc.disconnect();
            }
         }

         return responseCode == 200;
      }
   }

   // Proper tests, no unnecessary mocking ///////////////////////////////////////

   @Test
   public void checkAccessibleUrl() throws Exception {
      boolean accessible = ClassUnderTest.isUrlAccessible("http://google.com");

      assertTrue(accessible);
   }

   @Test(expected = UnknownHostException.class)
   public void checkInaccessibleUrl() throws Exception {
      ClassUnderTest.isUrlAccessible("http://inaccessible12345.com");
   }

   @Test
   public void checkUrlWhichReturnsUnexpectedResponseCode(
      @Mocked URL anyURL, @Mocked HttpURLConnection mockConn
   ) throws Exception {
      new Expectations() {{ mockConn.getResponseCode(); result = -1; }};

      boolean accessible = ClassUnderTest.isUrlAccessible("http://invalidResource.com");

      assertFalse(accessible);
   }

   // Lame tests with unnecessary mocking ////////////////////////////////////////

   @Test
   public void checkAccessibleUrl_withUnnecessaryMocking(
      @Mocked URL anyURL, @Mocked HttpURLConnection mockConn
   ) throws Exception {
      new Expectations() {{ mockConn.getResponseCode(); result = 200; }};

      boolean accessible = ClassUnderTest.isUrlAccessible("http://google.com");

      assertTrue(accessible);
   }

   @Test(expected = UnknownHostException.class)
   public void checkInaccessibleUrl_withUnnecessaryMocking(
      @Mocked URL anyURL, @Mocked HttpURLConnection mockConn
   ) throws Exception {
      new Expectations() {{ mockConn.connect(); result = new UnknownHostException(); }};

      ClassUnderTest.isUrlAccessible("http://inaccessible12345.com");
   }
}

(Verified with JMockit 1.47 on JDKs 8 & 9.)

(在 JDK 8 和 9 上使用 JMockit 1.47 验证。)

回答by minhaz

Although this thread has some good suggestion, but if any of you is not interested to use those third-party libraries here is a quick solution.

虽然这个线程有一些很好的建议,但如果你们中的任何人对使用这些第三方库不感兴趣,这里是一个快速的解决方案。

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 {

    }
}

And, this how you can set the desired behaviour

而且,这如何设置所需的行为

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

Note:It just mock 3 methods from HttpUrlConnectionand if you are using more method you need to make sure those are mock as well.

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