MockK Beginner Tutorial

Abhinay Gupta
3 min readMar 19, 2024

Understanding Mocking and MockK

  • Mocking: In unit testing, mocking involves creating simulated objects (mocks) that mimic the behavior of real dependencies. This allows you to isolate the unit under test (your code) from external components and test its functionality independently.
  • MockK: MockK is a lightweight, concise mocking library specifically designed for Kotlin. It offers a fluent API for creating mocks, defining their behavior, and verifying interactions with them during tests.

Prerequisites

  • Basic understanding of unit testing in Android with Kotlin
  • Android Studio or an IDE of your choice

Setting Up MockK

Add Dependency: Add the MockK library to your app module's build.gradle file:

dependencies {     testImplementation 'io.mockk:mockk:VERSION'
androidTestImplementation 'io.mockk:mockk-android:VERSION' }

Replace VERSION with the latest MockK version (check https://github.com/mockk/mockk).

Creating Mocks

mockk function: Use the mockk function to create a mock object of a specific class:

val mockRepository = mockk<MyRepository>()

Relaxed vs. Strict Mocks:

  • Relaxed (default): Relaxed mocks return default values (null, 0, etc.) for unstubbed methods. They’re suitable for most use cases.
  • Strict: Strict mocks throw exceptions for unstubbed methods, helping ensure you define all expected behavior. Use mockk(strict = true) for strict mode.

Defining Mock Behavior

  • every block: Use the every block to define how a mock should behave when its methods are called:
every { mockRepository.fetchData() } returns listOf(User("Alice"), User("Bob"))

This configures the mockRepository's fetchData method to always return a list of two users.

Verifying Mock Interactions

  • verify block: Use the verify block to assert that certain methods were called on a mock during your test:
verify { mockRepository.fetchData() wasCalled }
  • This verifies that fetchData was called at least once on the mockRepository mock.

Key MockK Features

  • Argument Capturing: Capture arguments passed to mock methods using capture:
val capturedId = capture<Long>() 
every { mockRepository.getById(capture(capturedId)) } returns User("Charlie")
// Later in your test verify
{ mockRepository.getById(10L) } // Assert that 10L was captured
  • Spying: Create a spy on an existing object using spyk:
val realObject = MyClass() 
val spyObject = spyk(realObject)
  • The spy allows you to observe real object behavior while also mocking specific methods.
  • Matching Arguments: Utilize advanced argument matching for complex scenarios using matchers provided by MockK or writing custom matchers. Refer to the MockK documentation for details.

Example: Unit Testing a ViewModel with MockK

Consider a simple ViewModel that fetches data from a repository:

Kotlin

class MyViewModel(private val repository: MyRepository) {
fun getUserList() {
val users = repository.fetchData()
// Update UI or perform other actions with users
}
}

Test with MockK:

Kotlin

class MyViewModelTest {
@get:Rule
val rule = InstantTaskExecutorRule() // Optional for LiveData testing if using LiveData
@Test
fun testUserListFetch() {
val mockRepository = mockk<MyRepository>()
every { mockRepository.fetchData() } returns listOf(User("David"), User("Eve"))
val viewModel = MyViewModel(mockRepository)
viewModel.getUserList() // Trigger the data fetch
verify { mockRepository.fetchData() wasCalled } // Assert data fetch was called
}
}

Additional Considerations

  • AndroidX Test Runner: MockK supports both JUnit and AndroidX Test Runner. Adjust your test class accordingly.
  • Advanced Mocking Techniques: MockK offers a rich set of features for more complex scenarios. Explore the documentation for details.

--

--