api: use retrofit-mock for tests

This commit is contained in:
Harsh Shandilya 2022-05-05 11:44:09 +05:30
parent 23ce5a489e
commit ad456c6141
No known key found for this signature in database
GPG key ID: 366D7BBAD1031E80
5 changed files with 64 additions and 88 deletions

View file

@ -12,6 +12,6 @@ dependencies {
testImplementation(libs.kotlinx.serialization.json) testImplementation(libs.kotlinx.serialization.json)
testImplementation(libs.kotlin.coroutines.core) testImplementation(libs.kotlin.coroutines.core)
testImplementation(kotlin("test-junit")) testImplementation(kotlin("test-junit"))
testImplementation(libs.retrofit.kotlinxSerializationConverter) { isTransitive = false } testImplementation(libs.retrofit.kotlinxSerializationConverter)
testImplementation(libs.testing.mockWebServer) testImplementation(libs.retrofit.mock)
} }

View file

@ -0,0 +1,32 @@
package dev.msfjarvis.claw.api
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlinx.coroutines.runBlocking
import retrofit2.Retrofit
import retrofit2.mock.MockRetrofit
import retrofit2.mock.create
class ApiTest {
private val retrofit = Retrofit.Builder().baseUrl(LobstersApi.BASE_URL).build()
private val api = MockRetrofit.Builder(retrofit).build().create<LobstersApi>().let(::FakeApi)
@Test
fun `api gets correct number of items`() = runBlocking {
val posts = api.getHottestPosts(1)
assertEquals(25, posts.size)
}
@Test
fun `posts with no urls`() = runBlocking {
val posts = api.getHottestPosts(1)
val commentsOnlyPosts = posts.asSequence().filter { it.url.isEmpty() }.toSet()
assertEquals(2, commentsOnlyPosts.size)
}
@Test
fun `post details with comments`() = runBlocking {
val postDetails = api.getPostDetails("d9ucpe")
assertEquals(7, postDetails.comments.size)
}
}

View file

@ -0,0 +1,27 @@
package dev.msfjarvis.claw.api
import dev.msfjarvis.claw.model.LobstersPost
import dev.msfjarvis.claw.model.LobstersPostDetails
import dev.msfjarvis.claw.util.TestUtils.getJson
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import retrofit2.mock.BehaviorDelegate
class FakeApi(private val delegate: BehaviorDelegate<LobstersApi>) : LobstersApi {
private val json = Json { ignoreUnknownKeys = true }
private val hottest: List<LobstersPost> = json.decodeFromString(getJson("hottest.json"))
private val postDetails: LobstersPostDetails =
json.decodeFromString(getJson("post_details_d9ucpe.json"))
override suspend fun getHottestPosts(page: Int): List<LobstersPost> {
return delegate.returningResponse(hottest).getHottestPosts(page)
}
override suspend fun getNewestPosts(page: Int): List<LobstersPost> {
TODO("Not yet implemented")
}
override suspend fun getPostDetails(postId: String): LobstersPostDetails {
return delegate.returningResponse(postDetails).getPostDetails(postId)
}
}

View file

@ -1,84 +0,0 @@
package dev.msfjarvis.claw.api
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import dev.msfjarvis.claw.util.TestUtils
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.fail
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import mockwebserver3.Dispatcher
import mockwebserver3.MockResponse
import mockwebserver3.MockWebServer
import mockwebserver3.RecordedRequest
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import org.junit.AfterClass
import org.junit.BeforeClass
import retrofit2.Retrofit
import retrofit2.create
@OptIn(ExperimentalSerializationApi::class)
class LobstersApiTest {
companion object {
private val contentType = "application/json".toMediaType()
private val webServer = MockWebServer()
private val okHttp = OkHttpClient.Builder().build()
private val json = Json { ignoreUnknownKeys = true }
private val retrofit =
Retrofit.Builder()
.client(okHttp)
.baseUrl("http://localhost:8080/")
.addConverterFactory(json.asConverterFactory(contentType))
.build()
private val apiClient = retrofit.create<LobstersApi>()
@JvmStatic
@BeforeClass
fun setUp() {
webServer.start(8080)
webServer.dispatcher =
object : Dispatcher() {
override fun dispatch(request: RecordedRequest): MockResponse {
val path = requireNotNull(request.path)
return when {
path.startsWith("/hottest") ->
MockResponse().setBody(TestUtils.getJson("hottest.json")).setResponseCode(200)
path.startsWith("/s/") ->
MockResponse()
.setBody(TestUtils.getJson("post_details_d9ucpe.json"))
.setResponseCode(200)
else -> fail("'$path' unexpected")
}
}
}
}
@JvmStatic
@AfterClass
fun tearDown() {
webServer.shutdown()
}
}
@Test
fun `api gets correct number of items`() = runBlocking {
val posts = apiClient.getHottestPosts(1)
assertEquals(25, posts.size)
}
@Test
fun `posts with no urls`() = runBlocking {
val posts = apiClient.getHottestPosts(1)
val commentsOnlyPosts = posts.asSequence().filter { it.url.isEmpty() }.toSet()
assertEquals(2, commentsOnlyPosts.size)
}
@Test
fun `post details with comments`() = runBlocking {
val postDetails = apiClient.getPostDetails("d9ucpe")
assertEquals(7, postDetails.comments.size)
}
}

View file

@ -6,6 +6,7 @@ dagger = "2.41"
hilt = "1.0.0" hilt = "1.0.0"
kotlin = "1.6.10" kotlin = "1.6.10"
material_motion = "0.8.4" material_motion = "0.8.4"
retrofit = "2.9.0"
richtext = "0.11.0" richtext = "0.11.0"
serialization = "1.3.2" serialization = "1.3.2"
sqldelight = "2.0.0-alpha02" sqldelight = "2.0.0-alpha02"
@ -52,13 +53,13 @@ multiplatform-paging = "io.github.kuuuurt:multiplatform-paging:0.4.7"
napier = "io.github.aakira:napier:2.5.0" napier = "io.github.aakira:napier:2.5.0"
r8 = "com.android.tools:r8:3.3.28" r8 = "com.android.tools:r8:3.3.28"
retrofit-kotlinxSerializationConverter = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0" retrofit-kotlinxSerializationConverter = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
retrofit-lib = "com.squareup.retrofit2:retrofit:2.9.0" retrofit-lib = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
retrofit-mock = { module = "com.squareup.retrofit2:retrofit-mock", version.ref = "retrofit" }
svg-transcoder = "org.pushing-pixels:aurora-tools-svg-transcoder-gradle-plugin:1.1.0" svg-transcoder = "org.pushing-pixels:aurora-tools-svg-transcoder-gradle-plugin:1.1.0"
sqldelight-androidDriver = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } sqldelight-androidDriver = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
sqldelight-extensions-coroutines = { module = "app.cash.sqldelight:coroutines-extensions-jvm", version.ref = "sqldelight" } sqldelight-extensions-coroutines = { module = "app.cash.sqldelight:coroutines-extensions-jvm", version.ref = "sqldelight" }
sqldelight-jvmDriver = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" } sqldelight-jvmDriver = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" }
sqldelight-primitiveAdapters = { module = "app.cash.sqldelight:primitive-adapters", version.ref = "sqldelight" } sqldelight-primitiveAdapters = { module = "app.cash.sqldelight:primitive-adapters", version.ref = "sqldelight" }
testing-mockWebServer = "com.squareup.okhttp3:mockwebserver3-junit4:5.0.0-alpha.7"
[plugins] [plugins]
compose = "org.jetbrains.compose:1.1.1" compose = "org.jetbrains.compose:1.1.1"