0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ラッパークラスの使いどき

Last updated at Posted at 2019-09-29

#概要
ラッパークラスの使いどきです。

#finalクラスをモック化したいとき
テストコードを書いていて、finalクラスをモック化したい場面があったのでラッパークラスにすることで対応しました。
元々引数にfinalクラスをとっていたメソッドだったのだけれど、それだとテストできないので引数をラッパークラスで取るようにしました。
最初からテスト駆動型で開発しておけばこういった事態にはならなかったのだろうか。。。難しい。

###元のコード


@Override
protected String doInBackground(URL... url) {
    HttpURLConnection con = null;
    URL urls = url[0];

    try {
        con = (HttpURLConnection)urls.openConnection();
        con.setRequestMethod("GET");
        con.connect();

        int resCd = con.getResponseCode();
        if (resCd != HttpURLConnection.HTTP_OK) {
            throw new IOException("HTTP responseCode:" + resCd);
        }

        BufferedInputStream inputStream = new BufferedInputStream(con.getInputStream());
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String line;
        while (true) {
            line = reader.readLine();
            if (line == null) {
                break;
            }
            mBuffer.append(line);
        }
        inputStream.close();
        reader.close();

    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        con.disconnect();
    }
    return mBuffer.toString();
}

###修正したコード

@Override
protected String doInBackground(URLWrapper... urlWrapper) {
    HttpURLConnection con = null;
    URLWrapper urls = urlWrapper[0];

    try {
        con = (HttpURLConnection)urls.openConnection();
        con.setRequestMethod("GET");
        con.connect();

        int resCd = con.getResponseCode();
        if (resCd != HttpURLConnection.HTTP_OK) {
            throw new IOException("HTTP responseCode:" + resCd);
        }

        BufferedInputStream inputStream = new BufferedInputStream(con.getInputStream());
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String line;
        while (true) {
            line = reader.readLine();
            if (line == null) {
                break;
            }
            mBuffer.append(line);
        }
        inputStream.close();
        reader.close();

    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        con.disconnect();
    }
    return mBuffer.toString();
}

doInBackgroundはAsyncTaskのメソッドです。
微妙な変化ですが、最初はjava.net.URLを引数にとっていたのですが、これだとURLはfinalクラスなのでモック化できないことに気づき、ラッパークラスに変更。
PowerMockitoを使うことも試したのですが、上手く使えなかったので、今はとりあえずこれで。
これで以下のようなテストコードがかけるようになりました。

@Test
public void test_doInBackground(){

    HttpURLConnection httpURLConnection = null;

    try{

        String rtnXml = "aaaaaaaaaaaa";
        // HttpURLConnectionのmock化
        httpURLConnection = mock(HttpURLConnection.class);
        when(httpURLConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
        when(httpURLConnection.getInputStream()).thenReturn(new ByteArrayInputStream(rtnXml.getBytes("utf-8")));

        // URLWrapperのmock化
        URLWrapper urlWrapper = mock(URLWrapper.class);
        when(urlWrapper.openConnection()).thenReturn(httpURLConnection);

        // ConfirmAsyncListenerImplのmock化
        ConfirmAsyncListenerImpl confirmAsyncListener = mock(ConfirmAsyncListenerImpl.class);

        // RestaurantAsync.doInBackground()のテスト
        RestaurantAsync restaurantAsync = new RestaurantAsync(confirmAsyncListener);
        assertThat(restaurantAsync.doInBackground(urlWrapper), is("aaaaaaaaaaaa"));


    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        httpURLConnection.disconnect();
    }

}

java.net.URLはmock化しようとするとコンパイルエラーが出るので、ラッパークラスを使うと対応できることがわかりました。

ちなみにラッパークラスは以下

URLWrapper.java

public class URLWrapper {

    private final URL url;

    public URLWrapper(URL url){
        this.url = url;
    }

    public URLConnection openConnection(){
        URLConnection urlConnection = null;
        try {
            urlConnection =  this.url.openConnection();
        }catch(IOException e){
            e.printStackTrace();
        }
        return urlConnection;
    }
}

引数をfinalクラスで取るのと、それのラッパークラスで取ることの違いやデメリットはあるのかしら。
それはまたわかったら追記します。

#まとめ

また気がついたら追記しようと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?