Mock is a substitute object that mimics the behavior of a real component and allows verifying interactions with it. Unlike Stub, which simply returns a predetermined value, Mock records the fact of method invocation, the arguments passed, and the number of calls. According to Mockito (2024), Mock is the most popular type of Test Double in Java and Kotlin projects, used in more than 70% of unit tests in mobile applications.
Key Takeaways
Mock is an object created by a mocking framework (Mockito, MockK, EasyMock) that simulates an interface or class and records all calls to its methods. The developer sets expectations: method X will be called with arguments Y and will return Z. After the test executes, the Mock verifies that the expectations matched the actual calls.
The term comes from the theatrical metaphor of Test Doubles: a Mock is an “impersonator” that does not just stand on stage (like a Dummy) but performs a role and verifies whether the interaction with it was correct. If the code under test did not call the method the Mock expected, or called it with incorrect arguments — the test fails with a violated expectation message.
A Mock is created through the framework factory: mockk<MyInterface>() or Mockito.mock(MyClass.java). The framework generates a proxy object that intercepts all method calls. Each call is compared against predefined expectations. If the call matches an expectation — the specified value is returned. If not — the Mock returns a default value or throws an exception, depending on the configuration.
Mock is essential when the code under test interacts with components that have side effects: sending data to a server, writing to a database, logging, analytics, navigation, showing system dialogs. Without Mocks, these interactions cannot be verified without running real infrastructure. According to the Google Testing Blog, Mock is the only way to verify that an application actually sent an analytics event without spinning up a test server.
The difference between Mock and Stub is one of the most debated topics in testing. Both types replace a real dependency, but in fundamentally different ways.
| Criterion | Mock | Stub |
|---|---|---|
| Main Question | Was the method called? | What result was returned? |
| Verification | Behavior (verify) | State (assert) |
| Data Return | Optional | Mandatory |
| Example | verify(analytics).logEvent(“click”) | assertEquals(5, repository.getCount()) |
| When to Use | Side effects | Data return |
A simple test to decide: ask yourself “if I delete this line of code, will the test fail?” If the test checks a return value — you need a Stub (assert-based verification). If the test checks that the code called a method with the correct arguments — you need a Mock (verify-based verification). This dichotomy follows from the Command-Query Separation pattern: methods that change state (commands) need Mocks; methods that return data (queries) need Stubs.
Choosing between Mockito and MockK is one of the first decisions when setting up the test stack for an Android project in Kotlin. Both libraries serve the same purpose, but with different approaches to Kotlin-specific features.
Mockito is the de facto standard for Java projects. Version 5.x supports mocking for final classes, static methods, and constructors thanks to the built-in MockMaker. For Kotlin projects, Mockito requires additional setup: mockito-kotlin extensions for improved syntax, mockito-inline for final classes. Mockito does not support Kotlin coroutines and suspend functions without additional adapters.
MockK was created specifically for Kotlin. It natively supports coroutines (coEvery, coVerify), sealed classes, data classes, object singletons, and extension functions. MockK syntax uses DSL with lambda blocks, which feels natural in Kotlin code. MockK also supports property mocking without additional setup — this is important for Android projects using LiveData, StateFlow, and Delegates.
// Mockito + mockito-kotlin
val repository = mock<UserRepository>()
whenever(repository.getUser(1)).thenReturn(user)
// MockK
val repository = mockk<UserRepository>()
every { repository.getUser(1) } returns user
Benchmarks (JVM Benchmark, 2024) show that MockK creates mock objects 15–20% faster than Mockito for Kotlin projects thanks to direct work with Kotlin bytecode rather than Java Reflections. For projects with thousands of unit tests, the difference in build speed can be noticeable: MockK saves 30–60 seconds on a full test run in large projects.
Let’s examine three scenarios: testing a ViewModel with Mock dependencies, testing a UseCase verifying API calls, and testing coroutines with coVerify.
class ProfileViewModelTest {
private val analytics = mockk<AnalyticsService>()
private val repo = mockk<UserRepository>()
private val vm = ProfileViewModel(repo, analytics)
fun `profile opened logs analytics event`() {
every { analytics.logEvent("profile_opened") } returns Unit
vm.onViewCreated()
verify { analytics.logEvent("profile_opened") }
}
}
class SendMessageUseCaseTest {
private val api = mockk<MessagingApi>()
private val useCase = SendMessageUseCase(api)
fun `send message with correct payload`() = runTest {
val message = Message(text = "Hello", userId = 42)
coEvery { api.sendMessage(any()) } returns MessageResult.Sent("msg_1")
val result = useCase.execute(message)
coVerify {
api.sendMessage(match {
it.text == "Hello" && it.userId == 42
})
}
assertTrue(result is MessageResult.Sent)
}
}
class OrderUseCaseTest {
private val api = mockk<OrderApi>()
private val useCase = OrderUseCase(api)
private val slot = slot<OrderRequest>()
fun `order request contains correct items`() = runTest {
coEvery { api.placeOrder(capture(slot)) } returns OrderResult.Placed("order_1")
useCase.execute(listOf("item_a", "item_b"))
assertEquals(2, slot.captured.items.size)
assertEquals("item_a", slot.captured.items[0])
}
}
Effective use of Mock in mobile development requires discipline. Violating these rules turns tests into fragile obstacles that break with every refactoring.
A hard rule: Mocks should only be created for dependencies that cross the application boundary: API clients, databases, file systems, system services (LocationManager, BluetoothAdapter, Camera). Internal application classes — domain entities, Value Objects, simple utilities — should not be replaced with Mocks. Their behavior is tested through real objects.
Each test should contain exactly one logical check — either verify (for Mock) or assert (for Stub). Do not mix state and behavior verification in a single test. If you need to check both an API call and its result — create two separate tests with different names. This rule, known as “one assert per test”, dates back to Kent Beck’s recommendations (2002).
Beyond basic mocking, there are advanced techniques that solve specific tasks in mobile development: testing multithreading, verifying Flow state, and partial mocking of real objects.
Spy (or partial mock) allows you to create an object that delegates calls to the real implementation but lets you override individual methods. In MockK, spyk is created based on a real class instance: val repo = spyk(InMemoryUserRepository()). Calls with expectations defined via every go through the Mock; the rest go through the real object. Spy is especially useful for testing legacy code where dependency injection hasn’t been implemented yet and you only need to override one method.
In modern Android projects using Jetpack Compose, ViewModel exposes state through StateFlow. MockK allows mocking Flow dependencies, and the Turbine library simplifies emission verification. The classic pattern: MockK for a UseCase returning a Flow, Turbine for verifying ViewModel emissions. This stack is recommended by the Android Testing documentation (Google, 2024) for projects using Kotlin Coroutines.
class SearchViewModelTest {
private val searchUseCase = mockk<SearchUseCase>()
private val vm = SearchViewModel(searchUseCase)
fun `search emits results`() = runTest {
coEvery { searchUseCase.search("android") } returns
flowOf(SearchResult.Success(listOf(Item("Android TDD"))))
vm.search("android")
vm.state.test {
val state = awaitItem()
assertTrue(state.items.isNotEmpty())
cancelAndIgnoreRemainingEvents()
}
}
}
Frequently Asked Questions
Mock is a concept, a type of Test Double that verifies behavior. Mockito is a library for creating Mock objects in Java and Android. Other libraries: MockK (Kotlin), EasyMock (Java), Cuckoo (iOS).
For testing suspend functions with Mock, use MockK (coEvery / coVerify) or Mockito with mockito-kotlin. MockK supports coroutines natively: coEvery defines the behavior of a suspend function, coVerify verifies its call inside a coroutine. All suspend calls must be executed inside runTest (kotlinx-coroutines-test).
Yes. In MockK, use returnsMany: every { api.getData() } returnsMany listOf(response1, response2). In Mockito — a chain of thenReturn(value1).thenReturn(value2). This is useful for testing behavior with sequential calls returning different responses.
In MockK, use the @MockK annotation with relaxed = true and call clearMocks(mock) in the @After method. In Mockito — Mockito.reset(mock). Best practice: create a new Mock for each test via @Before to eliminate cross-test interference.
MockK works correctly with sealed classes: every { useCase() } returns Result.Success(data). Mockito does not support sealed classes directly, requiring workarounds. This is one reason why MockK is recommended for Kotlin projects over Mockito.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also