Search code examples
swiftunit-testingkotlinpromisekotlin-coroutines

Kotlin equivalent of Swift Expectations/Promises


I am trying to write some UnitTests for my native mobile applications, but have ran into a roadblock in my Android Tests. Specifically, I am struggling to find an example of Kotlin's version of Swift's Expectations/Promises..

I've found examples of Kotlin Promises, but they seem to be way more complicated than needed...

For example, here is a test for the login API function in my iOS project:

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()
}

This is pretty simple to me. I have an asynchronous method login that has two possible completion blocks: success and failure; and I need to wait for one of them to complete before evaluating. To do this, I create a promise before the call, then I fulfill the promise in the two completion blocks, and I wait for the promise to fulfill before running my assertions.

Now in Kotlin, I have a similar test:

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

}

But I can't find an equivalent of swift's promises..

Does one exist in Kotlin? If not, how would I implement a version of my Swift's testLogin method in Kotlin?


Solution

  • You can use Kotlin coroutines, for example:

    @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)
    
                        })
        })   
    }
    

    To use coroutines you need to add next lines to app's build.gradle file dependencies:

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

    Hope it will help.