Kotlin
RxJava
Retrofit2
Moshi
Retrofit-Mock

Retrofit-MockでWebAPIをモック化する

はじめに

Androidアプリを作る際、WebAPIの仕様は決まっているものの、実際動くものがまだないということはよくあると思います。そんな時にRetrofitMockを使ってWebAPIをモック化することで、スムーズにアプリ開発を行うことができ、またWebAPIが使えるようになった時もスムーズに移行することができます。

RetrofitMock
https://github.com/square/retrofit/tree/master/retrofit-mock

今回は、Retrofit2 + RxJavaでWebAPIを利用するコードに、RetrofitMockを組み込みます。

環境

Kotlin
Retrofit2
RxJava
RetrofitMock
Moshi

セットアップ

gradle.build
    implementation 'com.squareup.retrofit2:retrofit:2.3.0'
    implementation "com.squareup.retrofit2:adapter-rxjava2:2.3.0"
    implementation 'com.squareup.retrofit2:converter-moshi:2.2.0'
    implementation 'com.squareup.retrofit2:retrofit-mock:2.3.0'

データクラス定義

今回はタグ一覧の取得APIのみ定義するため、Tagを表すデータクラスを作成
https://qiita.com/api/v2/docs#get-apiv2tags

QiitaTag.kt
data class QiitaTag(
        var followers_count: Int,
        var icon_url: String?,
        var id: String,
        var items_count: Int
)

RetrofitでAPI定義

今回はタグ一覧の取得APIのみ定義

IQiitaApi.kt
interface IQiitaApi {

    /**
     * https://qiita.com/api/v2/docs#get-apiv2tags
     */
    @GET("api/v2/tags")
    fun tags(
            @Query("page") page: Int? = null,
            @Query("per_page") per_page: Int? = null,
            @Query("sort") sort: String? = null
    ): Observable<List<QiitaTag>>
}

API呼び出し用オブジェクト生成

通常呼び出し用のcreate関数と、Mock作成用のcreateMock関数を作成。
注意点はNetworkBehaviorはデフォルトで応答するまで2000msになっているのでテストの効率を上げるため100msに変更。失敗率もデフォルトで3%になっており、たまにテストに失敗するため0%に変更。

QiitaApi.kt
class QiitaApi {
    companion object {
        fun create(): IQiitaApi {
            val retrofit = Retrofit.Builder()
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .addConverterFactory(MoshiConverterFactory.create())
                    .baseUrl("https://qiita.com/")
                    .build()

            return retrofit.create(IQiitaApi::class.java)
        }

        fun createMock(): IQiitaApi {
            val retrofit = Retrofit.Builder()
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .addConverterFactory(MoshiConverterFactory.create())
                    .baseUrl("http://example.com")
                    .build()

            val behavior = NetworkBehavior.create()
            behavior.setDelay(100, TimeUnit.MILLISECONDS)
            behavior.setFailurePercent(0)
            behavior.setErrorPercent(0)

            val mockRetrofit = MockRetrofit.Builder(retrofit)
                    .networkBehavior(behavior)
                    .build()

            val delegate = mockRetrofit.create(IQiitaApi::class.java)
            return MockQiitaApi(delegate)
        }
    }
}

テスト

androidTestでテストを実施。
テスト内容は適当ですが、エラーが発生しないこと、アイテム数が意図したものであることを確認。
QiitaのAPIとMockAPIで同じように呼び出しとテストができます。

インターネットに接続するため、"android.permission.INTERNET"のパーミッションが必要になります。

QiitaApiTest.kt
@RunWith(AndroidJUnit4::class)
class QiitaApiTest {
    @Test
    fun qiitaApi() {
        val api = QiitaApi.create()

        api.tags()
                .test()
                .assertNoErrors()
                .assertValue{
                    it.size == 20
                }
    }

    @Test
    fun mockApi() {
        val mock = QiitaApi.createMock()

        mock.tags()
                .test()
                .assertNoErrors()
                .assertValue {
                    it.size == 10
                }
    }
}