web-dev-qa-db-ja.com

URL接続をモックする方法

こんにちは私は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を使用してisUrlAccessible()メソッドの単体テストを行いたい。 whenNew()を使用してURLの作成をモックし、url.openConnection()が呼び出されたときに、別のモックHttpURLConnectionオブジェクトを返す必要があると感じています。しかし、これを実装する方法がわかりませんか?私は正しい方向に進んでいますか?誰かがこれを実装するのを手伝ってくれますか?

8
Nemin

解決策を見つけました。最初に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));

    }
5
Nemin

URLは最終クラスです。最終クラスをモックするために、JunitでPowerMockitoを使用できます。最終クラスをモックするには、テストクラスに@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);
    }
}

しかし、行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) 

このエラーを取り除くために、以下に示すように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);
    }
}

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

1
Pranab Thakuria

新しいURLインスタンスをモックできます

whenNew(URL.class)..

そのwhenNew呼び出しから、以前に作成したモックオブジェクトを返すようにしてください。

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

次に、必要に応じてモックに動作を追加できます。

1
Sezin Karli

mockitoライブラリを介してJava.net.URLクラスをモックするには、次の手順を実行する必要があります。

  • Src/tests/resourcesディレクトリに「mockito-extensions」という名前のディレクトリを作成します。
  • Org.mockito.plugins.MockMakerという名前のテキストファイルをフォルダにテキストを作成し、mock-maker-inlineファイルへのテキスト。
  • 次のようにクラスをモックできます。

コード:

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

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

(JDK8および9のJMockit1.47で検証済み。)

0
Rogério

このスレッドにはいくつかの良い提案がありますが、これらのサードパーティライブラリの使用に興味がない場合は、ここで簡単に解決できます。

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つのメソッドをモックするだけです。さらに多くのメソッドを使用している場合は、それらもモックであることを確認する必要があります。

0
minhaz