I am writing a unit test for my Datarepository layer which simply calls an interface.
I am using Kotlin, coroutines and MockK for unit testing.
In MockK, how can I verify that I have called apiServiceInterface.getDataFromApi() and has happened only once?
Should I put the code in runBlocking?
This is my code:
UnitTest
import com.example.breakingbad.api.ApiServiceInterface
import com.example.breakingbad.data.DataRepository
import io.mockk.impl.annotations.InjectMockKs
import io.mockk.impl.annotations.MockK
import io.mockk.verify
import org.junit.Test
Repository
class DataRepositoryTest {
@MockK
private lateinit var apiServiceInterface: ApiServiceInterface
@InjectMockKs
private lateinit var dataRepository: DataRepository
@Test
fun getCharacters() {
val respose = dataRepository.getCharacters()
verify { apiServiceInterface.getDataFromApi() }
}
}
class DataRepository @Inject constructor(
private val apiServiceInterface: ApiServiceInterface
) {
suspend fun getCharacters(): Result<ArrayList<Character>> = kotlin.runCatching{
apiServiceInterface.getDataFromApi()
}
}
Interface
interface ApiServiceInterface {
@GET("api/characters")
suspend fun getDataFromApi(): ArrayList<Character>
}
I think you should prefer using runTest instead of runBlocking or runBlockingTest.To tell you in brief about the three.
runBlocking allows you to call suspend functions by blocking a new coroutine and it blocks the current thread until it is completed.
runBlockingTest will immediately execute the suspending function skipping past any delay and enter coroutine block immediately unlike runBlocking which will wait for the amount of the delay
Since kotlinx.coroutines 1.6.0 release, runBlockingTest is deprecated in favour of runTest due to these reasons listed in the migration guide.
runTest() will automatically skip calls to delay() and handle uncaught exceptions. Unlike runBlockingTest() , it will wait for asynchronous callbacks to handle situations where some code runs in dispatchers that are not integrated with the test module.I hope that answers your question of what to choose among these 3 to test your suspending function. You code would look like this -:
@Test
fun getCharacters() = runTest {
val response = dataRepository.getCharacters()
coVerify { apiServiceInterface.getDataFromApi() }
}
Also note that as David mentioned above, because getDataFromApi() is asynchronous/suspending function as well, you will have to use coVerify instead of verify to mock the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With