java .lang.VerifyError Точная ссылка ожидается при попытке запустить блокировку Kotlin приостановлено удовольствие в Android - PullRequest
0 голосов
/ 07 апреля 2020

Я пытаюсь написать модульный тест, ожидающий завершения приостановленной функции kotlin, прежде чем проверять результаты следующим образом:

@Test
fun shouldSetupThingsProperly() {
    val context = InstrumentationRegistry.getInstrumentation().context
    runBlocking { MyObject.enable(context, false) }
    Assert.assertTrue( /* whatever usefull */ true)
}

Методы приостановки следующие:

object MyObject {

    @JvmStatic
    suspend fun enable(context: Context, enable: Boolean) {
        withContext(Dispatchers.IO) {
            // ... do some work
            wakeup(context)
        }
    }

    private suspend fun wakeup(context: Context) {
        withContext(Dispatchers.IO) {
            try {
                // setup things ...
            } catch (ignore: Exception) {}
        }
    }

}

Тестовый запуск заканчивается на:

java.lang.VerifyError: Verifier rejected class MyObject: java.lang.Object MyObject.enable(android.content.Context, boolean, kotlin.coroutines.Continuation) failed to verify: java.lang.Object MyObject.enable(android.content.Context, boolean, kotlin.coroutines.Continuation): [0x16] register v7 has type Reference: android.content.Context but expected Precise Reference: MyObject (declaration of 'MyObject' appears in /data/app/test-_rphd0tDrOp0KM-Bz09NWA==/base.apk!classes2.dex)
at MyObject.enable(Unknown Source:0)

Я не знаком с сопрограммой, и мне было интересно, как добиться правильного ожидания завершения включения приостановленной функции внутри теста или если ошибка была вызвана какой-то другая ошибка ...

1 Ответ

0 голосов
/ 07 апреля 2020

Тестирование сопрограмм - это хитрость, даже после некоторого опыта. Если вы можете импортировать, это будет очень полезно: https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-test

Если у вас есть эта функция, тестирование зависимостей становится намного более управляемым.

Прежде всего, если вы можете если у диспетчера вы используете эту переменную или параметр, который можно установить или переопределить, это поможет вам повысить тестируемость.

Что касается написания теста, вы можете сделать что-то вроде:

@Before
fun before() {
    Dispatchers.setMain(mainThreadSurrogate)
}

@Test
fun shouldSetupThingsProperly() = runBlockingTest {
    val context = InstrumentationRegistry.getInstrumentation().context
    MyObject.enable(context, false, Dispatchers.Main)
    Assert.assertTrue( /* whatever useful */ true)
}

У вашего объекта будет, я бы сказал, больше изменений

object MyObject {

    @JvmStatic
    suspend fun enable(context: Context, enable: Boolean, dispatcher: CoroutineDispatcher = Dispatchers.IO) {
         // If you need a return feel free to use withContext such as:
         // val result = withContext(dispatcher) { /* Return Value */ Any() }

        CoroutineScope(dispatcher).run {
            // ... do some work
            wakeup(context)
        }
    }

    private suspend fun wakeup(context: Context) {
        // Another coroutine scope is unnecessary here, it will inherit the parent scope automatically, so you can call
        // async functions here
        delay(200)

        try {
            // setup things ...
        } catch (exc: Exception) {
            // We had an issue
        }
    }
}
...