OkHttpのリクエスト周りのmockingが結構面倒くさかったのでメモ。
やりたい事
ベタ書きすると以下の様な事がしたい。単純にレスポンスをmockして返却したいデータをセットしたい。
OkHttpClient okHttpClient = mock(OkHttpClient.class); String body = "hoge"; ResponseBody responseBody = mock(ResponseBody.class); when(responseBody.string()).thenReturn(body); Response response = mock(Response.class); when(response.isSuccessful()).thenReturn(true); when(response.body()).thenReturn(responseBody); Call call = mock(Call.class); when(call.execute()).thenReturn(response); when(okHttpClient.newCall(any(Request.class))).thenReturn(call);
OkHttpClientはinjectして使う。テスト対象では以下のようなコードを実行している。
Request request = new Request.Builder() .url(url) .build(); Response response = client.newCall(request).execute(); if (response != null) { if (response.isSuccessful()) { String body = response.string(); //... } } //...
問題
ところが、ResponseBodyは各種メソッドがfinalなのでmockできない。Responseはfinal classなのでmockできない。このため上記のコードでは動かない。
環境
環境としては以下となる。robolectricを使っている場合なので、Androidでテストを動かす場合はdexmaker等を追加する必要がある。
dependencies { compile 'com.squareup.okhttp:okhttp:2.1.0' androidTestCompile('org.mockito:mockito-core:1.9.5') { exclude group: 'org.hamcrest' exclude module: 'objenesis' } }
テストコード
OkHttpの最新だとResponseBody.Builder
というのがあるらしい、しかしOkHttp2.1.0
ではない。という事でResponseBodyを実装しなければならない。ResponseはResponce.Builder
があるのでこれを使って作成する。Callはmock出来るので特に対応はいらない。
@Test public void mockingOkHttp() throws Exception { OkHttpClient okHttpClient = mock(OkHttpClient.class) File file = new File("test.html"); final long length = file.length(); final InputStream in = new FileInputStream(file); ResponseBody responseBody = new ResponseBody() { @Override public MediaType contentType() { return MediaType.parse("text/html"); } @Override public long contentLength() { return length; } @Override public BufferedSource source() { return Okio.buffer(Okio.source(in)); } }; Response response = new Response.Builder() .code(200) .body(responseBody) .protocol(Protocol.HTTP_1_0) .request(new Request.Builder() .url("") .build()) .build(); Call call = mock(Call.class); when(call.execute()).thenReturn(response); when(okHttpClient.newCall(any(Request.class))).thenReturn(call); // }
まとめ
ザックリ最低限のコードを書いた。これらをラップしたりして色々やると簡単にmockできる仕組みが作れると思う。しかしなんでResponseBodyやResponseはfinalなんだろうめんどくさい