Day 26: Server我也不要了,Mock Ktor 环境

Keyword: Ktor MockEngine, Unit Test
直到27日,完成KMM的测试功能放在
KMMDay27


有了基础的Mock环境,接下来我们要来Mock 网路请求.Ktor官方也有提供假的Mock引擎以便我们使用,不用自己再手动开发一个.

同样的,在gradle(shared)内我们进行Mock Engine的引用,我们是测试所以这次是放在commonTest内

//这是build.gradle.kts的soureSet内的Kotlin
val commonTest by getting {
            dependencies {
                ...
                implementation(Develop.Ktor.commonTest)
                implementation(Develop.Ktor.cio)
								...
            }
        }

而路径如下

//这是在buildSrc内的Kotlin
object Ktor{
        val commonTest = "io.ktor:ktor-client-mock:${Versions.ktor}"
        val cio = "io.ktor:ktor-client-cio:${Versions.ktor}"
    }

有了MockEnginge後,我们来建立一个使用MockEngine的MockApi

在commonTest下建立一个Mock package,然後里面放入我们的CafeApi的Mock

//这是在commonTest下的Kotlin
class CafeApiMock(mockEngine:HttpClientEngine) : CafeApi {
    companion object {
        val tag = CafeApiMock::class.simpleName
    }

    private val client = HttpClient(mockEngine) {
        install(JsonFeature) {
            serializer = KotlinxSerializer()
        }
    }

    override suspend fun fetchCafeFromApi(city: String): List<CafeResponseItem> {
        return client.get("https://cafenomad.tw/api/v1.2/cafes/")
    }
}

可以看到大部分都跟我们正常的CafeApiImpl相同,只是可以提供一个mockEngine来建立这个物件.

然後我们在commonTest下建立这个物件的测试流程,注意记得让commonTest去继承我们昨天写好的BaseTest,这样就能利用其中的方法建立一个给测试使用的coroutine,并且对双平台的独立测试来说没有差别,KMM会帮我们自动选择合适的实作.

//这是在commonTest底下的Kotlin语言
class CommonGreetingTest : BaseTest(){//继承了BaseTest来使用Coroutine
    @Test//标注Test说明这是一个Test Case
    fun KtorTest() {
        
    }
}

然後我们可以在KtorTest内建立我们的mockEngine,来控制我们的状态与内容

val mockEngine = MockEngine { request ->//不管什麽request
            respond(//都会回传这样
                content = ByteReadChannel("""[{"id":"000703fe-cf8a-43c8-bd83-c90cfd61915f","name":"觉旅咖啡","address":"太阳系","city":"taipei"}]"""),
                status = HttpStatusCode.OK,
                headers = headersOf(HttpHeaders.ContentType, "application/json")
            )
        }

并且把这个mockEngine丢进去产生CafeApiMock

val apiMock = CafeApiMock(mockEngine)

最後建立回传物件以作比较

val fakeResponseItem = CafeResponseItem("000703fe-cf8a-43c8-bd83-c90cfd61915f","太阳系","觉旅咖啡","taipei")
val responseItem = listOf(fakeResponseItem)

然後在Coroutine环境下进行测试

runTest{
    assertEquals(apiMock.fetchCafeFromApi("taipei"),result)
}

整份的测试内容如下

@Test
    fun KtorTest() {
        val mockEngine = MockEngine { request ->
            respond(
                content = ByteReadChannel("""[{"id":"000703fe-cf8a-43c8-bd83-c90cfd61915f","name":"觉旅咖啡","address":"太阳系","city":"taipei"}]"""),
                status = HttpStatusCode.OK,
                headers = headersOf(HttpHeaders.ContentType, "application/json")
            )
        }
        val apiMock = CafeApiMock(mockEngine)
        val fakeResponseItem = CafeResponseItem("000703fe-cf8a-43c8-bd83-c90cfd61915f","太阳系","觉旅咖啡","taipei")
        val result = listOf(fakeResponseItem)
        runTest{
            assertEquals(apiMock.fetchCafeFromApi("taipei"),result)
        }
    }

可以点旁边的绿色三角形来跑跑看.

明天我们会来跑看看SQLDelight的测试内容


<<:  Computer Architecture: Memory Hierarchy

>>:  DAY 16 - 树怪

SQL MD5 加密 & C# BASE64

C# BASE64 原由:厂商丢了编成 Base64 字串的东西来,接到後,要把它还原. strin...

Flutter学习Day1 dart&flutter安装(windows)

小弟弟第一次发文, 如有不好的地方 请多包涵 (≧∀≦)ゞ 由於我是vs code 使用爱好者 所以...

解决 IIS 的 PHP 发生 FastCGI 处理序超过设定的活动逾时问题

今天在执行 WordPress 上的版本更新时,因为更新档案太大,出现了错误「FastCGI 处理序...

单元测试&整合测试&回归测试

单元测试(Unit Testing) 单元测试既是一种测试工具,也是一种开发工具。现代软件开发人员通...

[DAY 16] 随机挑题与写入题目至新页面

上一次讲到的是取得资料范围後再读取里面的内容 可是通常出题应该要随机出题 不然永远只会写到相同的题目...