Unit Tests with Mockito and Jacoco in The Main Android Architectures — MVC, MVP, MVVM, Clean, MVI, VIPER, VIPER — part 3: MVP

André Figas
4 min readOct 14, 2022

--

MVP

If you have some doubts about this architecture, check my other article.

Model

This layer is entirely testable, but It was already done when we tested an MVC project. I was following an incremental methodology. So, I won’t repeat myself. Here I will just refer to my previous article.

View

The view layer definitely is not the proposal for this kind of test. That assertion is valid for all architectures. I would recommend you again read about Espresso.

Presenter

Success Cases

Setup

RX

RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() } RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }

We had to make changes on our main and io threads to move both to the same work queue. It would be handled as a synchronous job.

Instantiating

view = mock(PersonView::class.java)
model = PersonModel()
presenter = PersonPresenter(view, model)

Here I created a real instance of my model. But pay attention: It was possible in my case because my model is not real. Otherwise, If it would be a real API Rest, we should not make our test depends on an internet connection.
To surround this problem, you could mock our model and its response. You will see it working on failed tests.

Another great approach would be to work with local .json or XML files exactly as your API provides, but for now, this won’t be included in this article sequence.

Here I had to create a mock instance of View, to validate what our presenter will pass to it.

For sure, I must not mock our presenter, because do not make sense to submit a not real instance of what we wish to test.

onFetchPersonSuccess
given: our assumed scenario

//given
setupSuccess()

when: action that we wish to validate its consequences

//when
presenter.fetchPerson()

then: assertion about that consequences

//then val captor = ArgumentCaptor.forClass(String::class.java) inOrder(view)
verify(view, times(1)).showLoading()
verify(view, times(1)).hideLoading()
verify(view, times(1)).showPersonName(captureString(captor)) Assert.assertEquals(captor.value, “hello”)

We are basically validating here a sequence and quantity of interactions that happen to our view, and then we checked which argument that was passed to the method showPersonName

Failure Cases

Setup

Here, We did almost the same. But since, as I told you, our services are not a real API Rest implementation. It always returns a valid response. So, at moment we have to mock our model layer to provide an error instead of success.

onFetchPersonFail

//given
setupFail() `when`(model.providePerson()).thenReturn(Single.error(Throwable()))
//when
presenter.fetchPerson()
//then
inOrder(view)
verify(view, times(1)).showLoading()
verify(view, times(1)).hideLoading()
verify(view, times(1)).showPersonNameError()

Here, We did almost the same again. But since our model layer now is mocked, It is able only to return the default response like a null. We have to tell Mockito what you wish to return.

Cancel Cases

Setup

Since we expect to check how our application behaves when we cancel a pending request, we can not keep handling it as a synchronous process.
About our layers instances creation, again we have to mock a model layer. Because we wish to do force a delay. I don't want our service to be completed before I have a chance to cancel it.

fetchPersonCancel

Our release method returns true if there is really a request to be canceled.
So, basically, we created a delayed response.
Our assertion checks interactions and if we effectively cancel a request.

Now, let’s see which report can this implementation produce.

Generating Test Results Report

./gradlew app:testMvp_UnitTest

Output

app/build/reports/tests/testMvp_UnitTest/index.html

I hid some tests on our explanation to make it easy, but you can check the whole code on GitHub.

Generating Coverage Report

./gradlew app:testMvp_UnitTestCoverage

Output

app/build/reports/jacoco/testMvp_UnitTestCoverage/index.html

--

--