Тестирование сопрограмм в классе Presenter

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

 override fun viewCreated() {
        launch {
            val hasPermission = permissionChecker.execute() //suspended function
            if (hasPermission) {
                foo()
            } else {
                view.bar()
            }
         }

Ведущий также расширяет этот интерфейс:

interface CoroutinePresenter: CoroutineScope {

val job: Job

override val coroutineContext: CoroutineContext
    get() = Dispatchers.Main + job

fun stopAllActiveJobs() {
    coroutineContext.cancelChildren()
}

И приостановленная функция определяется следующим образом:

 suspend fun execute() : Boolean = withContext(Dispatchers.IO) {
    return@withContext class.foo()
}

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

@Test
fun `Test of Suspended Function`() = runBlocking {
    presenter.viewCreated()
    then(view).should().bar()
    ...
}

Я также добавил предложенную библиотеку для тестирования kotlinx-coroutines-test, но результат с ней все тот же. Я также пытался следовать предложению это, а также реализовать что-то вроде это, но все равно не повезло. Я думаю, что проблема заключается в фактическом создании другого потока всякий раз, когда запуск вызывается в презентере, и тест на самом деле не знает, как его дождаться. Я также пытался вернуть Работа и вызвать job.join(), но не получилось с NullPointerException.

Надеюсь, вы, ребята, можете мне помочь.

9
0
795
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я нашел решение для этого: следуя учебнику это, я настроил оба

@Before
fun setup() {
    Dispatchers.setMain(Dispatchers.Unconfined)
    ...
}
@After
fun tearDown() {
    Dispatchers.resetMain() // reset main dispatcher to the original Main dispatcher
}

И запустив весь блок запуск класса presenter внутри оператора runBlocking в тесте. Проблема была также связана с необъявленным исключением внутри приостановленной функции, которое на самом деле не было высмеивали, но было невидимым для моих глаз.

Теперь все работает нормально.

Во-первых, я настоятельно рекомендую указать ваш coroutineContext в качестве параметра следующим образом:

  class CoroutinePresenter(coroutineContext: CoroutineContext): CoroutineScope {
         init{
               _coroutineContext = coroutineContext
          }

         override val coroutineContext: CoroutineContext
                get() = _coroutineContext

         // Your Methods

    }

В вашей реальной среде:

 @YourScope
    @Provides
    fun providesCoroutinePresenter(coroutineContext:CoroutineContext ){
        return CoroutinePresenter()
    }
    @YourScope
    @Provides
    fun providesCoroutineContext(){
        return  Dispatchers.Main + job
    }

Во время модульного теста:

    @Before
    fun setUp() {
       coroutinePresenter  CoroutinePresenter(Dispatchers.Unconfined)
    }

    @Test
    fun `Should do something`(){
         //WHEN
         coroutinePresenter.doSomething(params)
         //THEN
         do your assertions
    }

Для получения дополнительной информации проверьте ТВЕРДЫЕ принципы и в этом случае Д.

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

Marco 10.07.2019 14:32

Другие вопросы по теме