Testing Suspending Functions
Learn how to test suspending functions and get an overview of their time dependency.
We'll cover the following...
Testing suspending functions in most cases is not different from testing normal functions. Take a look at the fetchUserData
below from FetchUserUseCase
. Checking whether it shows data, as expected, can be easily achieved thanks to a few fakes (or mocks) and simple assertions.
A fake class implements an interface, but contains fixed data and no logic. They help mimic a concrete behavior for testing.
Mocks are universal simulated objects that mimic the behavior of real objects in controlled ways. We generally create them using libraries, like MockK, which support mocking suspending functions. In the examples below, we have decided to use fakes to avoid using an external library.
Note: The example below will only throw an exception when both values passed to
assertEquals
are different.
package kotlinx.coroutines.app import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.runBlocking import org.junit.Test import kotlin.test.assertEquals import kotlinx.coroutines.ExperimentalCoroutinesApi class FetchUserUseCase( private val repo: UserDataRepository, ) { suspend fun fetchUserData(): User = coroutineScope { val name = async { repo.getName() } val friends = async { repo.getFriends() } val profile = async { repo.getProfile() } User( name = name.await(), friends = friends.await(), profile = profile.await() ) } } @ExperimentalCoroutinesApi class FetchUserDataTest { @Test fun `should construct user`() = runBlocking { // given val repo = FakeUserDataRepository() val useCase = FetchUserUseCase(repo) // when val result = useCase.fetchUserData() // then val expectedUser = User( name = "Ben", friends = listOf(Friend("some-friend-id-1")), profile = Profile("Example description") ) println(expectedUser) println(result) assertEquals(expectedUser, result) } class FakeUserDataRepository : UserDataRepository { override suspend fun getName(): String = "Ben" override suspend fun getFriends(): List<Friend> = listOf(Friend("some-friend-id-1")) override suspend fun getProfile(): Profile = Profile("Example description") } } interface UserDataRepository { suspend fun getName(): String suspend fun getFriends(): List<Friend> suspend fun getProfile(): Profile } data class User( val name: String, val friends: List<Friend>, val profile: Profile ) data class Friend(val id: String) data class Profile(val description: String)
Note: Our method ...