在模拟类中捕获具有通用结果的suspend lambda参数

时间:2020-04-26 19:12:47

标签: android junit5 mockk

我想知道是否可以使用MockK和JUnit5捕获具有常规结果的暂停lambda。 我已经尝试了几种方法,最近一次尝试运行测试时出现了KotlinNullPointerException。

这是代码,具有完整的类依赖关系和测试:

class Test {
data class Result<out T>(val status: ResultStatus, val data: T?, val exception: Exception?) {
    companion object {
        fun <T> success(data: T?): Result<T> {
            return Result(ResultStatus.SUCCESS, data, null)
        }

        fun <T> error(exception: Exception): Result<T> {
            return Result(ResultStatus.ERROR, null, exception)
        }

        fun <T> loading(data: T? = null): Result<T> {
            return Result(ResultStatus.LOADING, data, null)
        }
    }
}

class Dep1() {
    fun <R> methodToMock(viewModelScope: CoroutineScope, block: suspend CoroutineScope.() -> R): MutableLiveData<Result<R>> {
        val result = MutableLiveData<Result<R>>()
        result.value = Result.loading()

        viewModelScope.launch {
            try {
                var asyncRequestResult: R? = null
                withContext(Dispatchers.Default) {
                    asyncRequestResult = block()
                }
                result.value = Result.success(asyncRequestResult)
            } catch (cancellationException: CancellationException) {
            } catch (exception: Exception) {
                result.value = Result.error(exception)
            }
        }

        return result
    }
}

class Dep2() {
    fun methodToAssert(): Boolean {
        println("Called")
        return true
    }
}

class ClassToTest(private val dep1: Dep1, private val dep2: Dep2) {
    fun methodToCall(coroutineScope: CoroutineScope): MutableLiveData<Result<Boolean>> {
        return dep1.methodToMock(coroutineScope) {
            dep2.methodToAssert()
        }
    }
}

private val dep1: Dep1 = mockk()
private val dep2: Dep2 = mockk(relaxed = true)
private val mViewModelScope: CoroutineScope = GlobalScope

@Test
fun `Check if is calling the required methods correctly`() {
    val classToTest = ClassToTest(dep1, dep2)

    val transactionLambda = slot<suspend CoroutineScope.() -> Boolean>()
    coEvery { dep1.methodToMock(mViewModelScope, capture(transactionLambda)) } coAnswers {
        MutableLiveData(Result.success(transactionLambda.captured.invoke(mViewModelScope)))
    }

    classToTest.methodToCall(mViewModelScope)

    verify { dep2.methodToAssert() }
}

}

1 个答案:

答案 0 :(得分:0)

如果有人也遇到此问题,我可以使用every而不是coEvery并调用coInvoke()插槽方法来解决此问题:

every { dep1.methodToMock(mViewModelScope, capture(transactionLambda)) } answers  {
    MutableLiveData(Result.success(transactionLambda.coInvoke(mViewModelScope)))
}