About
JavaでHTTPクライアントのテストを書こうとしていたら、okhttp/mockwebserverなるものを見つけたのですが、これが便利だったので紹介します。
サンプルコードの一部は、GitHubにあります。
題材
RestAPIクライアントの実装にRetrofitを利用する状況を想定し、サンプル題材としてGitHub APIにアクセスするクライアントを考えます。
GitHubService.java
public interface GitHubService {
/**
* 指定されたユーザのリポジトリリストを取得.
*
* @param user
* @reeturn Call<List<Repository>>
*/
@GET("/users/{user}/repos")
Call<List<Repository>> listRepos(@Path("user") String user);
}
GitHubServiceの使い方としては、次のようなコードになると思います。
当然ですが、本物のGitHub APIのURLをRetrofitのbaseUrlに設定します。
final Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
final GitHubService service = retrofit.create(GitHubService.class);
final Call<List<Repository>> listRepos = service.listRepos("hosopy");
listRepos.enqueue(new Callback<List<Repository>>() {
@Override
public void onResponse(Response<List<Repository>> response, Retrofit retrofit) {
}
@Override
public void onFailure(Throwable throwable) {
}
});
GitHubServiceをテストする
JUnitでGitHubServiceのテストを書きたいとします。
テストなので、本物のGitHub APIにアクセスさせることは避けたいのですが、MockWebServerを利用することで、Webサーバのモックを用意することが出来ます。
MockWebServerを利用して、GitHubServiceをテストするコードはこのように書くことが出来ます。
(Matcherにhamcrest-allを使っています)
GitHubServiceTest.java
@RunWith(JUnit4.class)
public class GitHubServiceTest extends TestCase {
private static final int TIMEOUT = 10000;
@Test(timeout = TIMEOUT)
public void testListReposSuccess() throws IOException, InterruptedException {
final BlockingQueue<String> events = new LinkedBlockingQueue();
// MockWebServerとMockResponseを設定
final MockWebServer mockWebServer = new MockWebServer();
final MockResponse mockResponse = new MockResponse()
.setResponseCode(200)
.setHeader("Content-Type", "application/json")
.setBody("[{\"name\":\"Bolts-iOS-Sample\", \"html_url\":\"https://github.com/hosopy/Bolts-iOS-Sample\"}," +
"{\"name\":\"dotfiles\",\"html_url\":\"https://github.com/hosopy/dotfiles\"}]");
mockWebServer.enqueue(mockResponse);
mockWebServer.start();
// baseUrlにMockWebServerのURLを設定
final Retrofit retrofit = new Retrofit.Builder()
.baseUrl(mockWebServer.url("/").toString())
.addConverterFactory(GsonConverterFactory.create())
.build();
final GitHubService service = retrofit.create(GitHubService.class);
final Call<List<Repository>> listRepos = service.listRepos("hosopy");
// テスト
listRepos.enqueue(new Callback<List<Repository>>() {
@Override
public void onResponse(Response<List<Repository>> response, Retrofit retrofit) {
for (Repository repository : response.body()) {
events.offer(repository.getName());
events.offer(repository.getHtmlUrl());
}
}
@Override
public void onFailure(Throwable throwable) {
}
});
assertThat(events.take(), is("Bolts-iOS-Sample"));
assertThat(events.take(), is("https://github.com/hosopy/Bolts-iOS-Sample"));
assertThat(events.take(), is("dotfiles"));
assertThat(events.take(), is("https://github.com/hosopy/dotfiles"));
mockWebServer.shutdown();
}
}
MockWebServerは他にも色々な使い方が出来るようなので、GitHubのドキュメントを参照してみて下さい。