项目中目前使用Ktor来网络请求, 测试DataSource的时候需要构建一个HttpClient,下面提供了一个简单的封装类KtorMock
以下是简单用法:
internal class DataSource(private val httpClient: HttpClient) {
suspend fun getAds(): List<Ad> {
...
}
}
internal class DataSourceTest {
private val ktorMock: KtorMock = KtorMock()
private val dataSource: DataSource = DataSource(ktorMock.httpClient)
// happy path
@Test
fun `given a valid json response then getAds returns ads data`() = runTest {
val json = """
{
"code": "0",
"message": "OK",
"data": [{
"id":"1",
"name":"Test Ad",
"imageUrl":"https://example.com/image.jpg",
}]
}
""".trimIndent()
ktorMock.mockRespondOk(json)
dataSource.getAds() shouldBe listOf(
Ad(
id="1",
name="Test Ad",
imageUrl="https://example.com/image.jpg",
),
)
}
// bad path
@Test
fun `given bad request, then getAds returns empty list`() {
ktorMock.mockRespondBadRequest()
dataSource.getAds() shouldBe listOf()
}
}
internal class KtorMock {
private val respondProvider = mockk<(MockRequestHandleScope) -> HttpResponseData>()
private val mockEngine = MockEngine { _ ->
respondProvider(this)
}
val httpClient = HttpClient(mockEngine) {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
explicitNulls = false
})
}
defaultRequest {
header(HttpHeaders.ContentType, ContentType.Application.Json.toString())
}
}
private fun mockResponse(block: MockRequestHandleScope.() -> HttpResponseData) {
val slot = slot<MockRequestHandleScope>()
every { respondProvider(capture(slot)) } answers {
slot.captured.block()
}
}
fun mockRespondOk(content: String) {
mockResponse {
respond(
content = content,
headers = headersOf(HttpHeaders.ContentType to listOf(ContentType.Application.Json.toString())),
)
}
}
fun mockRespondBadRequest() {
mockResponse {
respondBadRequest()
}
}
}