#39 OkHttpのMockWebServerを試す
OkHttpにはテスト用のMockWebServer
があります。今回はこれを使ってテスト(Androidプロジェクト)を書いてみます。
公式ドキュメントはこちらにあります。
ライブラリを追加する
テストでしか使用しないので、testImplementation
で追加します。アプリ本体で使用しているOkHttpとバージョンを合わせておきましょう。
dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.8.0'
testImplementation 'com.squareup.okhttp3:mockwebserver:4.8.0'
}
テスト対象のコードを書く
ログインメソッドがあり、呼ぶとサーバーにPOSTリクエストを投げることにします。コンストラクタではbaseUrl
として、ホストまでの部分(例えばhttps://api.example.com)を受け取ることにします。レスポンスの処理はサンプルなので見ていません。
class UserRepositoryImpl(
private val client: OkHttpClient,
private val baseUrl: String,
): UserRepository {
override suspend fun login(email: String, password: String): User {
val contentType = "application/json; charset=utf8".toMediaType()
val json = "{\"email\":\"$email\",\"password\":\"$password\"}"
val requestBody = json.toRequestBody(contentType)
val request = Request.Builder().apply {
post(requestBody)
url("${baseUrl}/post")
}.build()
val response = withContext(Dispatchers.IO) {
client.newCall(request).execute()
}
if (response.code != 200) {
throw Exception("Error")
}
val body = withContext(Dispatchers.IO) {
response.body?.string() ?: ""
}
// bodyの中身を見て、idとnameを取り出すのが正しいコード
return User(id= "uid1", name = "Moke")
}
}
モックサーバーを作って起動する
次はテスト側です。JVMテストで行うので、app/src/testの下にテストクラスを作ります。
class UserRepositoryImplTest {
private lateinit var server: MockWebServer
private lateinit var repo: UserRepositoryImpl
@Before
fun setup() {
// インスタンスを作って
server = MockWebServer()
// レスポンスをセットして
server.enqueue(MockResponse().apply {
setResponseCode(200)
setBody("{}")
throttleBody(bytesPerPeriod = 10, period = 1, unit=TimeUnit.SECONDS)
})
// 起動!
server.start()
repo = UserRepositoryImpl(
OkHttpClient(),
server.url("").toString().dropLast(1)
)
}
@After
fun tearDown() {
// 終わったらとめる
server.shutdown()
}
}
@Before
でサーバーを起動し、@After
でサーバーをとめるようにしています。server.enqueue()
で、リクエストに対するレスポンスをセットします。テスト対象が複数回リクエストを投げる場合は複数個セットしておきましょう。
throttleBody()
を使うと、レスポンスをゆっくり返してくれます。上記の例でば、10バイト送信する度に1秒待ちつつレスポンスを返します。
サーバーをstart()
で起動した後は、テスト対象にbaseUrlを伝えます。server.url("")
は
http://localhost:12345/
のように、ルートへのパス(/)を含んだ文字列を返すので、dropLast(1)
で末尾の/を抜いています。
テストを記述する
最後にテストメソッドです。
class UserRepositoryImplTest {
private lateinit var server: MockWebServer
private lateinit var repo: UserRepositoryImpl
@Test
fun login() {
runBlocking {
val user = repo.login("demo", "pass")
val req1 = withContext(Dispatchers.IO) {
server.takeRequest()
}
assertEquals("/post", req1.path)
}
}
}
テスト対象がsuspend fun
なのでrunBlocking
を使います。
MockWebServerはtakeRequest()
でどのようなリクエストを受け取ったか返してくれます。
ここではテスト対象のコードが/post
を呼んだか確認しています。
まとめ
OkHttpのMockWebServerを使ってAndroidのJVMテストを書いてみました。テストのための機能は 一通り揃っているので、ぜひ使ってみてください。