Как протестировать функцию, запускающую сопрограмму, в инструментальном тесте Android?

В моем проекте Android Kotlin у меня есть класс с функцией, запускающей сопрограмму, которую я хочу протестировать с помощью инструментального теста (не модульного теста).

Вот как это выглядит:

class DemoClass
{
    fun demo(liveData: MutableLiveData<String>)
    {
        CoroutineScope(IO).launch {
            val result = doStuff()
            withContext(Main) { liveData.value = result }
        }
    }
}

В моем инструментальном тестовом классе я пробовал следующее:

@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest
{
    @ExperimentalCoroutinesApi
    @Test
    fun testCoroutine() = runBlockingTest {
        val demoClass = DemoClass()
        val liveData = MutableLiveData<String>()
        demoClass.demo(liveData)
        assertEquals("demo", liveData.value)
    }
}

К сожалению, это не работает. Похоже, что runBlockingTest {} доступен только для модульного тестирования, а не для инструментального тестирования. Вот моя ошибка при запуске теста:

java.lang.NoClassDefFoundError: Failed resolution of: Lkotlinx/coroutines/test/TestBuildersKt;

Итак, как я могу проверить DemoClass.demo() и значение liveData в инструментальном тесте?

Спасибо.

ИЗМЕНИТЬ

Я также пробовал это:

@ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest
{
    private val testDispatcher = TestCoroutineDispatcher()

    @Before
    fun setup() {
        Dispatchers.setMain(testDispatcher)
    }

    @After
    fun tearDown() {
        Dispatchers.resetMain()
        testDispatcher.cleanupTestCoroutines()
    }

    @Test
    fun testCoroutine(): Unit = runBlocking {
        val demoClass = DemoClass()
        val liveData = MutableLiveData<String>()
        demoClass.demo(liveData)
        assertEquals("demo", liveData.value)
    }
}

Тест работает, но я получил это:

java.lang.AssertionError: 
Expected :demo
Actual   :null

person matteoh    schedule 13.06.2020    source источник


Ответы (1)


Я использовал только runBlocking {} вместо runBlockingTest для достижения успеха.

Я знаю, что технически runBlockingTest - правильный способ, я считаю, что основное отличие заключается в том, как обрабатываются задержки.

Возможно, попробуйте эти флаги в своем тестовом классе, чтобы обойти эту разницу,

    @JvmField
    val instantExecutorRule = InstantTaskExecutorRule()

    @ExperimentalCoroutinesApi
    @get:Rule
    var mainCoroutineRule = MainCoroutineRule()
person Mike dg    schedule 13.06.2020
comment
Все еще не работает для меня. Не могли бы вы привести небольшой пример, случайно? - person matteoh; 13.06.2020
comment
хм, вы проверили, что у вас есть androidTestImplementation 'org.jetbrains.kotlinx: kotlinx-coroutines-test: 1.3.7' в вашем build.gradle? также добавил некоторые подробности - person Mike dg; 13.06.2020
comment
Спасибо, и да, у меня есть эта реализация, но мне все еще не удается заставить ее работать (кстати, это testImplementation). Я отредактировал свой пост, для вашего сведения. - person matteoh; 13.06.2020
comment
если вы хотите, чтобы библиотека была доступна для инструментальных тестов, а не для модульных тестов, вы должны использовать androidTestImplementation, как предложил Майк. - person Gustavo; 13.06.2020