Kotlin 相当于 Swift Expectations/Promises

Kotlin equivalent of Swift Expectations/Promises

我正在尝试为我的本机移动应用程序编写一些单元测试,但在我的 Android 测试中遇到了 运行 障碍。具体来说,我正在努力寻找 Swift 的 Expectations/Promises..

的 Kotlin 版本的示例

我找到了 Kotlin Promises 的示例,但它们似乎比需要的要复杂得多...

例如,这里是我的 iOS 项目中登录 API 功能的测试:

func testLogin() {

    /// Prepare for login
    if CURRENT_USER != nil {
        logout()
    }

    /// Login
    let promise = expectation(description: "User is logged in.")

    // 1. Given
    var isSuccess: Bool = false

    // 2. When
    User.login(username: maleUsername, password: malePassword, success: {
        isSuccess = true
        promise.fulfill()
    }) { (_, agreeToTerms) in
        XCTFail()
    }
    wait(for: [promise], timeout: maxTimeOut)

    // 3. Then
    XCTAssertNotNil(CURRENT_USER)
    XCTAssertTrue(isSuccess)

    /// Logout
    logout()
}

这对我来说很简单。我有一个异步方法 login,它有两个可能的完成块:successfailure;在评估之前,我需要等待其中一个完成。为此,我在调用之前创建了一个 promise,然后我 fulfill 两个完成块中的 promise,我 在 运行 我的断言之前等待 兑现承诺。

现在在Kotlin中,我有一个类似的测试:

private val loginFragment = LoginFragment()

@Test
fun loginTest() {

    val username = ""
    val password = ""

    // TODO: Create Promise

    loginFragment.loginViewModel
            .login(username, password)
            .observe(loginFragment, Observer {
                loginFragment.activity?.onResult(it?.result,

                        onSuccess = {
                            // TODO: Fill Promise
                        },
                        onValidationError = {
                            // TODO: Fail Test
                        })
            })

    // TODO: Assertions

}

但我找不到与swift的承诺等价的东西..

Kotlin 中有吗?如果没有,我将如何在 Kotlin 中实现我的 Swift 的 testLogin 方法的一个版本?

您可以使用 Kotlin 协程,例如:

@Test
fun loginTest() {
    val result = runBlocking {
        val loginResult = login() 
        loginResult
    }
    if (result == "Success") {
        // do your work when Success
    } else {
        // do your work when Error
    }
}
suspend fun login(): String = suspendCoroutine { continuation ->
    val username = ""
    val password = ""
    loginFragment.loginViewModel
    .login(username, password)
    .observe(loginFragment, Observer {
        loginFragment.activity?.onResult(it?.result,

                    onSuccess = {
                        continuation.resume("Success")
                    },
                    onValidationError = {
                        continuation.resume("Error") // take a look for other methods, e.g. resumeWithException(exception)

                    })
    })   
}

要使用协程,您需要将下一行添加到应用程序的 build.gradle 文件依赖项中:

final KOTLIN_COROUTINES_VERSION = '1.0.1'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$KOTLIN_COROUTINES_VERSION"

希望对您有所帮助。

我发现 this Kotlin Promise lib 更接近 Swift Promises。 使用这个库你的测试会喜欢。

@Test
fun loginTest() {
    val username = ""
    val password = ""

    Promise<Boolean, Exception> { promise ->
        loginFragment.loginViewModel
            .login(username, password)
            .observe(loginFragment, Observer {
                loginFragment.activity?.onResult(it?.result,

                    onSuccess = {
                        promise.resolve(true)
                    },
                    onValidationError = {
                        promise.reject(Exception("Login error"))
                    })
            })
    }.whenComplete {
        when (it) {
            is Promise.Result.Success -> {
                assert(it.value)
            }
        }
    }
}

我在 20 分钟内写了一个看起来像 swift 的 expectation 的实现,但他并不复杂,仅用于简单的情况就可以很好地工作。

typealias XCTestExceptionHandler = (KTTestException?) -> Unit

fun TestCase.expectation(description: String): KTTestExpectation {
    return KTTestExpectation(description)
}

fun TestCase.waitFor(expectation: KTTestExpectation, timeout: Long, handler: XCTestExceptionHandler) {
    expectation.handler = handler

    Thread.sleep(timeout)
    expectation.timedOut()
}

class KTTestExpectation(private val description: String) {
    private var isFulfilled = false
    var handler: XCTestExceptionHandler? = null

    fun fulfill() {
        Handler(Looper.getMainLooper()).postDelayed({
            invokeHandlerWith(null)
        }, 2)
    }

    fun timedOut() {
        invokeHandlerWith(KTTestException("Timed out: $description"))
    }

    private fun invokeHandlerWith(error: KTTestException?) {
        if (isFulfilled) return
        isFulfilled = true
        handler?.invoke(error)
        error?.let { Assert.fail("Timed out: $description") }
    }
}

class KTTestException(message:String): Exception(message)

使用:

    fun testExpectation() {
        var nb = 0
        val expectation = expectation("Test")

        MyAsyncFunc {
            nb = 5
            expectation.fulfill()
        }

        waitFor(expectation, 1000) { error ->
            assertEquals(5, nb)
        }
    }

如果有人有勇气将原始代码转换为 Kotlin 链接如下: https://github.com/apple/swift-corelibs-xctest/blob/main/Sources/XCTest/Public/Asynchronous/XCTWaiter.swift

https://github.com/apple/swift-corelibs-xctest/blob/main/Sources/XCTest/Public/Asynchronous/XCTestExpectation.swift