2013年3月26日火曜日

AndroidでMockitoを使ってDefaultHttpClientのモックを作る時の注意点

AndroidでMockitoを使ってDefaultHttpClientのモックを作るのにエライ苦労したのでまとめておきたいと思う。

ポイントはMockitoはfinalの付いているメソッドをモックすることはできないということだ。

なので、DefualtHttpClient.execute(HttpUriRequest req)メソッドはfinalなのでmockitoでモックすることができない。

そこで、まだfinalになっていないスーパークラスのAbstractHttpClient(implements HttpClient)を使ってモックする。

実際のテストコードはこんな感じだ。

// サーバーが返すべきJSON
String json = "{\"responseCode\":500,\"key\":\"EApBAu\"}";
StringBufferInputStream sbis = new StringBufferInputStream(json);

// サーバーが返すべきJSONを返すHttpEntitiyをモック
HttpEntity mockHttpEntity = Mockito.mock(HttpEntity.class);
Mockito.when(mockHttpEntity.getContent()).thenReturn(sbis);

// サーバーが返すHTTPステータスを500と仮定したStatusLineをモック
StatusLine mockStatusLine = Mockito.mock(StatusLine.class);
Mockito.when(mockStatusLine.getStatusCode()).thenReturn(500);

// HttpEntityとStatusLineのモックを返すHttpResponseをモック
HttpResponse mockResponse = Mockito.mock(HttpResponse.class);
Mockito.when(mockResponse.getStatusLine()).thenReturn(mockStatusLine);
Mockito.when(mockResponse.getEntity()).thenReturn(mockHttpEntity);

// HttpResponseのモックを返すHttpClientをモック
HttpClient mockHttpClient = Mockito.mock(HttpClient.class);
Mockito.when(mockHttpClient.execute(Mockito.notNull(HttpUriRequest.class))).thenReturn(mockResponse);

テストされる側のコードはこんな感じにしておけば、結局DefaultHttpClientを使うことになるので問題ない。

// テストでモックオブジェクトを使うためにDefaultHttpClientでなくわざとHttpClient型にしとく
public HttpClient client = new DefaultHttpClient();

ただし、「client.getConnectionManager().shutdown();」するのは要注意だ。

DefaultHttpClientならもちろん問題ないが、HttpClientのモックの場合、いつまでたってもシャットダウンされないで処理が滞ってしまう。

そこでこんな風にした。

if (client instanceof DefaultHttpClient) {
  Log.d("TAG", "接続をシャットダウンします");
  client.getConnectionManager().shutdown();
} else {
  Log.d("TAG", "HttpClientは恐らくモックオブジェクトなので接続のシャットダウンをスキップします");
}

ふう。