こんにちは。I.Tです。
今回は、JUnitでモック(JMockit)を使用し、下記を実現したいと思います。
・検証メソッドの戻り値を指定(複数回呼び出しに対応)
・検証メソッドが呼び出し回数を検証
・検証メソッドの引数を検証(複数回呼び出しに対応)
モック(JMockit)については
下記の記事でも解説しておりますので、ぜひご覧ください。
外部サーバへのHTTPリクエストをJUnit(モック)でテストしよう
検証環境
- Eclipse 4.4.1
- Java 1.7
- JUnit 4.12
- JMockit 1.17
- httpclient 4.4.1
Eclipse動作確認手順
Eclipseプロジェクトを添付しておりますので
動作を確認しながらご覧いただければ幸いです。
opentone_labs_201511.zip
- 「ファイル」-「インポート」-「既存プロジェクトをワークスペースへ」を選択
- 「アーカイブ・ファイルの選択」でopentone_labs_201511.zipを選択しインポート
- プロジェクトを右クリックし、「実行」-「JUnit テスト」
- JUnitが全て緑(成功)していることを確認
テスト対象機能
下記がテスト対象機能です。
引数のURLに対してGETでHTTPリクエストを行い、HTTPステータスを返却しています。
1回目のリクエストのHTTPステータスが504 Gateway timeoutの場合のみ、2回目をリクエストしています
・HttpServiceImpl.java(テスト対象機能)
[java]
public class HttpServiceImpl implements HttpService {
/**
* コンストラクタ
*/
public HttpServiceImpl() {
}
@Override
public int requestUrl(String url) throws IOException {
int statusCode = request(url);
// Gateway timeoutの場合は再実行
if (statusCode == HttpStatus.SC_GATEWAY_TIMEOUT) {
statusCode = request(url);
}
// HTTPステータスを返却
return statusCode;
}
private int request(String url) throws IOException {
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
int statusCode;
try {
// CloseableHttpClientを生成
httpClient = HttpClients.createDefault();
// GETでHTTPリクエストを作成
HttpGet request = new HttpGet(url);
// HTTPリクエストを行い、HTTPレスポンスを取得
response = httpClient.execute(request);
// HTTPレスポンスよりHTTPステータスを取得
statusCode = response.getStatusLine().getStatusCode();
} finally {
if (httpClient != null) {
// CloseableHttpClientをclose
httpClient.close();
}
if (response != null) {
// CloseableHttpResponseをclose
response.close();
}
}
// HTTPステータスを返却
return statusCode;
}
}
[/java]テストコード
テスト対象機能においてHTTPリクエストを行っているhttpClient.executeメソッドについて
下記3点の検証をしたいと思います(※HttpClientについてはこちらを参照)
- 1回目のリクエストが504 Gateway timeoutとなった場合、httpClient.executeが2回呼ばれていること
- 2回ともGETでリクエストされていること
- 2回とも引数のURL(★dummy★)が指定されていること
「new NonStrictExpectations() 」の箇所で検証メソッドの戻り値を指定します。
resultに複数回指定することで、1回目はHTTPステータス=504 Gateway timeout、2回目は200 OKが返却・・・のように設定できます。
「new Verifications()」の箇所で検証メソッドが呼び出された回数と引数を検証します。
回数は、「times = 2」で検証しています。
引数は、httpClient.executeの引数に指定された内容がactualHttpUriRequestListにリストで格納されるので、それを検証しています。
・UnusedMockedHttpServiceTest.java
[java]
@Test
public void モックの呼ばれた回数とモックに渡されたパラメータを検証() throws Exception {
// 1回目はHTTPステータス504 Gateway timeout、2回目は200 OKが返却されるようモックに設定
new NonStrictExpectations() {
{
// モックの対象メソッドを指定
mockHttpClient.execute((HttpUriRequest) any);
// CloseableHttpClient#executeの戻り値を生成
result = new HttpResponseImplDummy(HttpStatus.SC_GATEWAY_TIMEOUT);
result = new HttpResponseImplDummy(HttpStatus.SC_OK);
}
};
// モックを使用するので、実際には ★dummy★ にリクエストされない
int actual = httpService.requestUrl("★dummy★");
// HTTPステータスが200 OKであること
assertThat(actual, is(HttpStatus.SC_OK));
// モックが期待通りに呼ばれたか検証
new Verifications() {
{
// 呼ばれた時の引数を取得
List<HttpUriRequest> actualHttpUriRequestList = new ArrayList<>();
mockHttpClient.execute(withCapture(actualHttpUriRequestList));
// 対象メソッドが呼ばれた回数が2回であること
times = 2;
// 1回目:GETでリクエストされていること
assertThat(actualHttpUriRequestList.get(0), instanceOf(HttpGet.class));
// 1回目:URIが期待通りであること
assertThat(actualHttpUriRequestList.get(0).getURI().toString(), is("★dummy★"));
// 2回目:GETでリクエストされていること
assertThat(actualHttpUriRequestList.get(1), instanceOf(HttpGet.class));
// 2回目:URIが期待通りであること
assertThat(actualHttpUriRequestList.get(1).getURI().toString(), is("★dummy★"));
}
};
}
[/java]モック(JMockit)活用により
・検証メソッドの戻り値を指定(複数回呼び出しに対応)
・検証メソッドが呼び出し回数を検証
・検証メソッドの引数を検証(複数回呼び出しに対応)
が実現できました。

