Как вызвать метод интерфейса представления модульного теста в Presenter с сопрограммами на Android? - PullRequest
0 голосов
/ 09 июля 2020

Я работаю над Android какое-то время, но мне впервые приходится писать несколько модульных тестов. У меня есть шаблон проектирования в MVP, поэтому в основном у меня есть Presenter, у которого есть контракт (представление), и он заполнен kotlin, используя сопрограммы.

Вот мой класс Presenter: Repository и SomeOtherRepository - это kotlin object, поэтому он вызывает методы напрямую (идея состоит в том, чтобы не менять способ работы на самом деле)

    class Presenter(private val contractView: ContractView) : CoroutinePresenter() {

         fun someMethod(param1: Obj1, param2: Obj2) {
             
             launch {
                 try {
                   withContext(Dispatchers.IO) {
                      val data = SomeService.getData() ?: run { throw Exception(ERROR) } // getData() is a suspend function

                      Repository.doRequest(param1, param2) // doRequest() is a suspend function also
                   }.let { data ->
                     
                     if (data == null) {
                        contractView.onError(ERROR)
                     } else {
                       if (SomeOtherRepository.validate(data)) {
                          contractView.onSuccess()
                       } else {
                          contractView.onError(ERROR)
                       }
                     }

                 } catch (exception: Exception) {
                   contractView.onError(exception)
                 }
             }
         }
    }

Итак, моя цель - создать модульный тест для этого класса Presenter поэтому я создал следующий класс, чтобы протестировать Presenter. Вот реализация теста: я прочитал много статей и ссылок на stackoverflow, но все еще имею проблему.

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


@ExperimentalCoroutinesApi
class TestCoroutineRule(
    private val testDispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher()
) : TestWatcher(), TestCoroutineScope by TestCoroutineScope() {

    override fun starting(description: Description?) {
        super.starting(description)
        Dispatchers.setMain(testDispatcher)
    }

    override fun finished(description: Description?) {
        super.finished(description)
        Dispatchers.resetMain()
        testDispatcher.cleanupTestCoroutines()
    }

    private fun TestCoroutineRule.runBlockingTest(block: suspend () -> Unit) =
        testDispatcher.runBlockingTest { block() }
}

реализация PresenterTest:


@ExperimentalCoroutinesApi
class PresenterTest {

    @get:Rule
    val testCoroutineRule = TestCoroutineRule()

    @Mock
    private lateinit var view: ContractView

    @Mock
    private lateinit var repository: Repository

    private lateinit var presenter: Presenter

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        presenter = Presenter(view)
    }

    @Test
    fun `test success`() =
        testCoroutineRule.runBlockingTest {
            // Given
            val data = DummyData("test", 0L)

            // When
            Mockito.`when`(repository.doRequest(param1, param2)).thenReturn(data)

            // Then
            presenter.someMethod("test", "test")

            // Assert / Verify
            Mockito.verify(view, Mockito.times(1)).onSuccess()
        }
}

Проблема, с которой я столкнулся, заключается в следующей ошибке: Wanted but not invoked: view.onSuccess(); Actually there were zero interactions with this mock.

ContractView реализован в Activity, поэтому мне было интересно, нужно ли мне использовать Robolectri c, чтобы вызвать метод onSuccess () в контексте Activity. Я также думаю, что у меня может быть проблема с использованием сопрограмм. Я много чего пробовал, но всегда получал эту ошибку в представлении onSuccess et onError, если бы кто-нибудь мог помочь, был бы очень признателен :)

1 Ответ

0 голосов
/ 11 июля 2020

Могут быть другие проблемы, но, как минимум, вас не хватает:

Mockito.`when`(someOtherRepository.validate(data)).thenReturn(data)
Mockito.`when`(someService.getData()).thenReturn(data)

Используйте свой отладчик и проверьте свои журналы, чтобы проверить, что делает тест

...