简体   繁体   中英

How to unit test view interface method called in Presenter with coroutines on Android?

I'm working on Android for a while but it's the first time I have to write some unit tests. I have a design pattern in MVP so basically I have my Presenter, which have a contract (view) and it's full in kotlin, using coroutines.

Here is my Presenter class: The Repository and SomeOtherRepository are kotlin object so it's calling methods directly (The idea is to not change the way it's working actually)

    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)
                 }
             }
         }
    }

So the goal for me is to create unit test for this Presenter class so I created the following class in order to test the Presenter . Here is the Test implementation: I read a lot of articles and stackoverflow links but still have a problem.

I setup a TestCoroutineRule which is like this:


@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() }
}

And here is the PresenterTest implementation:


@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()
        }
}

The problem I have is the following error Wanted but not invoked: view.onSuccess(); Actually there were zero interactions with this mock Wanted but not invoked: view.onSuccess(); Actually there were zero interactions with this mock .

The ContractView is implemented in the Activity so I was wondering if I have to use Robolectric in order to trigger the onSuccess() method within the Activity context. I also think that I have a problem regarding the usage of coroutines maybe. I tried a lot of things but I always got this error on the onSuccess et onError view, if anyone could help, would be really appreciated:)

There could be other problems, but at a minimum you are missing:

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

Use your debugger and check your logs to inspect what the test is doing

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM