こんにちは。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)活用により
・検証メソッドの戻り値を指定(複数回呼び出しに対応)
・検証メソッドが呼び出し回数を検証
・検証メソッドの引数を検証(複数回呼び出しに対応)
が実現できました。