Blog Infos
Author
Published
Topics
, , , ,
Published

Hey there! In this article, we’ll dive into how to use MockK to test Android-specific components like ViewModelLiveDataActivity, and Fragment. We’ll also explore integrating MockK with libraries like JUnit and Coroutines, and cover how to test asynchronous code with Flows and suspend functions.

Let’s get started!

Mocking ViewModels and LiveData
Why Test ViewModels?

ViewModels are a crucial part of Android’s architecture for managing UI-related data. Testing ViewModels ensures that your business logic is correct and that LiveData updates as expected.

Example of Mocking a ViewModel with MockK

Let’s say you have a UserViewModel that fetches user data and exposes it via LiveData:

class UserViewModel(private val userRepository: UserRepository) : ViewModel() {
    val userName = MutableLiveData<String>()
    fun loadUser(userId: Int) {
        val name = userRepository.getUser(userId)
        userName.value = name
    }
}

Here’s how to test this ViewModel using MockK and JUnit:

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.Observer
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
class UserViewModelTest {
    @get:Rule
    val rule = InstantTaskExecutorRule()
    @Test
    fun `test loadUser updates userName LiveData`() {
        val mockUserRepository = mockk<UserRepository>()
        val viewModel = UserViewModel(mockUserRepository)
        val observer = mockk<Observer<String>>(relaxed = true)
        // Stub the repository
        every { mockUserRepository.getUser(1) } returns "John Doe"
        // Observe the LiveData
        viewModel.userName.observeForever(observer)
        // Call the function
        viewModel.loadUser(1)
        // Verify the LiveData was updated
        verify { observer.onChanged("John Doe") }
    }
}
Key Points
  • Use InstantTaskExecutorRule to execute LiveData tasks synchronously during testing.
  • Mock observers with mockk<Observer<T>>().
  • Verify LiveData changes using verify { observer.onChanged(value) }.
Testing Activities and Fragments with MockK
Why Test Activities and Fragments?

Activities and Fragments are central to your app’s UI and user interaction. Testing them ensures that they behave correctly, especially when interacting with ViewModels, LiveData, and other components.

Mocking Dependencies in an Activity

Let’s say you have an Activity that displays user details via a UserViewModel:

class UserActivity : AppCompatActivity() {
    private val viewModel: UserViewModel by lazy { ViewModelProvider(this).get(UserViewModel::class.java) }
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_user)
        viewModel.userName.observe(this) { name ->
            findViewById<TextView>(R.id.userNameTextView).text = name
        }
    }
}
Testing the Activity

Here’s how to test this Activity using MockK and JUnit:

import androidx.lifecycle.MutableLiveData
import androidx.test.core.app.ActivityScenario
import io.mockk.every
import io.mockk.mockk
import org.junit.Assert.assertEquals
import org.junit.Test
class UserActivityTest {
    @Test
    fun `test UserActivity displays user name correctly`() {
        // Mock the ViewModel
        val mockViewModel = mockk<UserViewModel>(relaxed = true)
        val fakeLiveData = MutableLiveData<String>()
        every { mockViewModel.userName } returns fakeLiveData
        // Launch the Activity
        val scenario = ActivityScenario.launch(UserActivity::class.java)
        scenario.onActivity { activity ->
            // Inject the mocked ViewModel
            activity.viewModel = mockViewModel
            fakeLiveData.value = "Jane Doe"
            val textView = activity.findViewById<TextView>(R.id.userNameTextView)
            assertEquals("Jane Doe", textView.text)
        }
    }
}
  • Use ActivityScenario to launch and interact with Activities.
  • Inject mocks into the Activity to isolate it from real dependencies.
  • Verify the UI updates as expected.
Integrating MockK with Coroutines and JUnit
Why Test Coroutines?

Coroutines make asynchronous programming easier, but they also introduce complexities in testing. MockK provides coEvery and coVerify to handle suspending functions.

Example of Testing a Coroutine Function

Suppose you have a UserRepository with a suspend function:

class UserRepository {
    suspend fun getUser(id: Int): String = "Real User"
}

Here’s how to test a ViewModel that uses this repository:

class UserViewModel(private val userRepository: UserRepository) : ViewModel() {
    val userName = MutableLiveData<String>()
    fun loadUser(userId: Int) {
        viewModelScope.launch {
            val name = userRepository.getUser(userId)
            userName.value = name
        }
    }
}
Test with MockK and Coroutines

 

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.mockk
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
class UserViewModelCoroutineTest {
    @get:Rule
    val rule = InstantTaskExecutorRule()
    @Test
    fun `test loadUser updates userName LiveData with coroutine`() = runTest {
        val mockRepository = mockk<UserRepository>()
        val viewModel = UserViewModel(mockRepository)
        coEvery { mockRepository.getUser(1) } returns "John Doe"
        viewModel.loadUser(1)
        coVerify { mockRepository.getUser(1) }
        assertEquals("John Doe", viewModel.userName.value)
    }
}

 

  • Use coEvery and coVerify for suspending functions.
  • Use runTest to test coroutine code.
  • Dispatchers.Main can be overridden with Dispatchers.Unconfined during tests.

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

, ,

Intro to unit testing coroutines with Kotest & MockK

In this workshop, you’ll learn how to test coroutines effectively using the Kotest and MockK libraries, ensuring your app handles concurrent tasks efficiently and with confidence.
Watch Video

Intro to unit testing coroutines with Kotest & MockK

Jaroslaw Michalik
Kotlin GDE

Intro to unit testing coroutines with Kotest & MockK

Jaroslaw Michalik
Kotlin GDE

Intro to unit testing coroutines with Kotest & MockK

Jaroslaw Michali ...
Kotlin GDE

Jobs

No results found.

Testing Flows with MockK

Flows are a powerful way to handle streams of data. Testing Flows can be tricky, but MockK and kotlinx.coroutines provide tools to make it easier.

Example of Testing a Flow

Suppose you have a repository that returns a Flow of user names:

class UserRepository {
    fun getUserFlow(): Flow<String> = flow {
        emit("John Doe")
    }
}
Test the Flow

 

import io.mockk.coEvery
import io.mockk.mockk
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Test
class UserRepositoryFlowTest {
    @Test
    fun `test getUserFlow emits correct value`() = runTest {
        val mockRepository = mockk<UserRepository>()
        coEvery { mockRepository.getUserFlow() } returns flowOf("Jane Doe")
        val result = mockRepository.getUserFlow().toList()
        assertEquals(listOf("Jane Doe"), result)
    }
}

 

Key Points
  • Use flowOf to create simple Flow mocks.
  • Use toList() to collect Flow emissions for assertions.
Conclusion

You’ve learned how to:

  • Mock ViewModels, LiveData, Activities, and Fragments with MockK.
  • Integrate MockK with JUnit and Coroutines.
  • Test asynchronous code using coEverycoVerify, and Flows.

With these skills, you’re well-equipped to write robust and reliable unit tests for your Android apps. Happy testing!

This article is previously published on proandroiddev.com.

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
It’s one of the common UX across apps to provide swipe to dismiss so…
READ MORE
blog
Hi, today I come to you with a quick tip on how to update…
READ MORE
blog
Automation is a key point of Software Testing once it make possible to reproduce…
READ MORE
blog
Drag and Drop reordering in Recyclerview can be achieved with ItemTouchHelper (checkout implementation reference).…
READ MORE
Menu