how to mock a URL connection

前端 未结 6 974
感情败类
感情败类 2020-12-06 01:50

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

public static boolean isUrlAccessible(final Str         


        
相关标签:
6条回答
  • 2020-12-06 02:12

    You can mock new Url instance with

    whenNew(URL.class)..
    

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

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

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

    0 讨论(0)
  • 2020-12-06 02:12

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

    
    @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:

    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:

    @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

    0 讨论(0)
  • 2020-12-06 02:17

    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:

    @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));
    
        }
    
    0 讨论(0)
  • 2020-12-06 02:17

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

    • 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-inline text into the file.
    • you can mock the class like the following:

    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);
        }
    }
    
    0 讨论(0)
  • 2020-12-06 02:28

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

    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.)

    0 讨论(0)
  • 2020-12-06 02:31

    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 HttpUrlConnection and if you are using more method you need to make sure those are mock as well.

    0 讨论(0)
提交回复
热议问题