MockWebServerを使ってAndroid通信をテストする - Re.Ra.Ku アドベントカレンダー day 16

Re.Ra.Ku アドベントカレンダー 16日目です。

こんにちは、安部です。

MockWebServerを使うと通信部分のモックが簡単にできるので、使い方を紹介したいと思います。

okhttp/mockwebserver at master · square/okhttp

(試してませんが、Android以外のJavaプロジェクトでも使えると思います。)

セットアップ

build.gradleに追加します。今回サンプルで使うOkHttpとRetrofitも追加してます。

testCompile 'com.squareup.okhttp3:mockwebserver:3.4.1'

compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'

OkHttp

OkHttpを使った通信のテストのサンプルです。

テスト対象コード

URLをもらって通信して結果を返却するだけのコードです。実践的ではないですが、使い方をわかりやすくするために単純にしています。

モックのURLを渡せるようにエンドポイントのURLはコンストラクタで設定しています。

public class Connection {

    private String baseURL;

    public Connection(String baseURL) {
        this.baseURL = baseURL;
    }

    public String run() throws IOException {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(baseURL + "test").build();

        Response response = client.newCall(request).execute();
        return response.body().string();
    }
}

テストコード

簡単なテストコードです。

基本的な使い方はレスポンスを設定して、URLを取得して、そこにアクセスする感じです。

public class ConnectionTest {

    private MockWebServer server;

    @After
    public void tearDown() throws Exception {
        if (server != null) {
            // モックサーバーを停止
            server.shutdown();
        }
    }

    @Test
    public void run() throws Exception {
        server = new MockWebServer();
        // レスポンスで返したいものを設定
        MockResponse response = new MockResponse()
                // header
                .addHeader("Content-Type", "text/plain")
                // status code
                .setResponseCode(200)
                // body
                .setBody("レスポンス");

        server.enqueue(response);

        // モックサーバーのURL設定と取得
        HttpUrl url = server.url("/");

        // 実行
        Connection connection = new Connection(url.toString());
        String result = connection.run();

        // レスポンスを確認
        assertThat(result, is("レスポンス"));

        // リクエストを確認
        RecordedRequest request = server.takeRequest();
        assertThat(request.getPath(), is("/test"));
    }
}

Retrofit + RxJava

RetrofitとRxJavaを使ったサンプルです。

テスト対象コード

想定として、GitHubのユーザー情報を取得する感じのものです。

RxJavaのObservableを返す形になっています。使う側は取得したObservableをsubscribeする感じになるかと思います。

public interface GitHubService {

    @GET("users/{user}")
    Observable<User> getUser(@Path("user") String user);

}
public class GitHubAPI {

    private String baseURL;

    public GitHubAPI(String baseURL) {
        this.baseURL = baseURL;
    }

    public Observable<User> getUser(String user) {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseURL)
                // Gson
                .addConverterFactory(GsonConverterFactory.create())
                // RxJava Adapter
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();

        GitHubService service = retrofit.create(GitHubService.class);

        return service.getUser(user);
    }
}
public class User {

    public String id;

    public String name;
}

テストコード

MockWebServerを作るあたりは先程の例と変わりませんが、Observableをテストする方法として、TestSubscriberを使っています。TestSubscriberを使うとだいぶテストが書きやすくなると思います。

public class GitHubAPITest {

    private MockWebServer server;

    @After
    public void tearDown() throws Exception {
        if (server != null) {
            // モックサーバーを停止
            server.shutdown();
        }
    }

    @Test
    public void getUser() throws Exception {
        server = new MockWebServer();

        MockResponse response = new MockResponse()
                .addHeader("Content-Type", "application/json")
                .setResponseCode(200)
                .setBody("{\"id\":123456,\"name\":\"Kenji Abe\"}");

        server.enqueue(response);

        HttpUrl url = server.url("/");
        GitHubAPI api = new GitHubAPI(url.toString());

        // Test用のSubscriber
        TestSubscriber<User> testSubscriber = TestSubscriber.create();

        api.getUser("STAR-ZERO").subscribe(testSubscriber);

        // 終了するまで待つ
        testSubscriber.awaitTerminalEvent();
        // 完了を確認
        testSubscriber.assertCompleted();

        // onNextにあたるイベントからデータ取得
        User user = testSubscriber.getOnNextEvents().get(0);

        assertThat(user.id, is(123456));
        assertThat(user.name, is("Kenji Abe"));

        // リクエストを確認
        RecordedRequest request = server.takeRequest();
        assertThat(request.getPath(), is("/users/STAR-ZERO"));
    }

}

まとめ

MockWebServerを使うことで通信部分のテストが可能になります。使い方もそこまで難しくはないと思うのでオススメです。