Захватить лямбда-параметр приостановки с обобщенным результатом c в фиктивном классе - PullRequest
0 голосов
/ 26 апреля 2020

Я хочу знать, возможно ли перехватить лямбда-приостановку с обобщенным результатом c с помощью MockK и JUnit5. Я пробовал несколько способов, и в самом последнем у меня появляется 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 голосов
/ 30 апреля 2020

Если у кого-то также возникла эта проблема, я смог решить ее, используя every вместо coEvery и вызвав метод слота coInvoke():

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