0
0
Android Kotlinmobile~15 mins

MockK for mocking in Android Kotlin - Deep Dive

Choose your learning style9 modes available
Overview - MockK for mocking
What is it?
MockK is a Kotlin library used to create mock objects for testing Android apps. It helps simulate parts of your app that are hard to test directly, like network calls or database access. By using MockK, you can check if your code behaves correctly without needing the real parts. This makes testing faster and more reliable.
Why it matters
Without mocking tools like MockK, testing complex app parts would be slow, unreliable, or impossible. You would have to rely on real servers or databases, which can fail or slow down tests. MockK solves this by letting you replace those parts with simple fake versions that behave predictably. This improves developer confidence and speeds up app development.
Where it fits
Before learning MockK, you should understand basic Kotlin programming and unit testing concepts. After mastering MockK, you can explore advanced testing techniques like integration testing and UI testing frameworks.
Mental Model
Core Idea
MockK lets you create pretend versions of app parts to test your code in isolation and control their behavior.
Think of it like...
Using MockK is like practicing a play with stand-in actors before the real cast arrives. The stand-ins behave like the real actors so you can rehearse scenes without waiting for everyone.
┌───────────────┐      ┌───────────────┐
│ Your Code     │─────▶│ MockK Mock    │
│ (Under Test)  │      │ (Fake Object) │
└───────────────┘      └───────────────┘
         │                      ▲
         │ Calls                │ Returns controlled
         ▼                      │ responses
┌───────────────┐               │
│ Real Dependency│──────────────┘
│ (e.g., Server) │
└───────────────┘
Build-Up - 7 Steps
1
FoundationWhat is Mocking in Testing
🤔
Concept: Introduce the idea of mocking as replacing real parts with fake ones during tests.
When testing, sometimes parts of your app depend on things like servers or databases. These can be slow or unreliable. Mocking means creating fake versions of these parts that behave in a controlled way. This helps test your code without depending on real external parts.
Result
You understand why mocking is useful to isolate code and make tests faster and more reliable.
Understanding mocking is key to writing tests that focus only on the code you want to check, avoiding outside distractions.
2
FoundationSetting Up MockK in Kotlin
🤔
Concept: Learn how to add MockK to your Android project and write a simple mock.
Add MockK to your build.gradle dependencies with: implementation 'io.mockk:mockk:1.13.5' to create a mock object: val mockObj = mockk() This mock can replace a real object in tests.
Result
You can create mock objects in your Kotlin tests ready to simulate behavior.
Knowing how to set up MockK is the first step to using it effectively in your tests.
3
IntermediateDefining Mock Behavior with every and returns
🤔Before reading on: do you think mocks automatically return real data or do you need to specify responses? Commit to your answer.
Concept: Learn how to tell mocks what to return when called.
Mocks do not know what to return by default. You use 'every' to define behavior: every { mockObj.someFunction() } returns "Hello" This means when someFunction is called on mockObj, it returns "Hello".
Result
Mocks respond with specified values, letting you control test scenarios.
Understanding how to define mock responses lets you simulate different situations your code might face.
4
IntermediateVerifying Calls with verify Block
🤔Before reading on: do you think tests can check if a function was called on a mock? Commit to yes or no.
Concept: Learn how to check if your code called certain functions on mocks.
Use 'verify' to check calls: verify { mockObj.someFunction() } This test passes only if someFunction was called on mockObj during the test.
Result
You can confirm your code interacts correctly with dependencies.
Verifying calls helps ensure your code uses other parts as expected, catching logic errors.
5
IntermediateMocking Coroutines and Suspend Functions
🤔Before reading on: do you think mocking suspend functions differs from regular ones? Commit to yes or no.
Concept: Learn how to mock Kotlin suspend functions used in coroutines.
For suspend functions, use coEvery and coVerify: coEvery { mockObj.suspendFunction() } returns "Data" coVerify { mockObj.suspendFunction() } This handles asynchronous calls properly in tests.
Result
You can test coroutine-based code with mocks that behave correctly in async contexts.
Knowing coroutine-specific mocking avoids common pitfalls in testing asynchronous code.
6
AdvancedMocking Constructors and Object Singletons
🤔Before reading on: can MockK replace real constructors or singleton objects? Commit to yes or no.
Concept: Learn how to mock object singletons and constructors to control hard-to-replace parts.
Use mockkObject to mock singletons: mockkObject(Singleton) every { Singleton.method() } returns 42 Use mockkConstructor to mock new instances: mockkConstructor(MyClass::class) every { anyConstructed().method() } returns "Mocked" This lets you test code that creates new objects or uses singletons.
Result
You can control even tightly coupled code parts in tests.
Mocking constructors and objects unlocks testing for legacy or complex code that otherwise resists isolation.
7
ExpertHandling Relaxed Mocks and Capturing Arguments
🤔Before reading on: do you think mocks always require explicit behavior definitions? Commit to yes or no.
Concept: Explore advanced features like relaxed mocks that return defaults and capturing arguments passed to mocks.
Relaxed mocks return default values automatically: val relaxedMock = mockk(relaxed = true) Capture arguments to check what was passed: val slot = slot() every { mockObj.method(capture(slot)) } returns Unit After test, slot.captured holds the argument. These features simplify tests and let you inspect interactions deeply.
Result
Tests become easier to write and more powerful in checking behavior.
Using relaxed mocks and argument capturing reduces boilerplate and reveals hidden bugs in interactions.
Under the Hood
MockK works by generating proxy objects at runtime that intercept calls to mocked methods. When your code calls a mock, MockK's proxy checks if you defined a behavior for that call and returns the specified response. It also records calls for verification. For coroutines, it handles suspend functions by wrapping them to work with Kotlin's coroutine machinery. MockK uses bytecode manipulation and reflection to create these proxies without changing your original code.
Why designed this way?
MockK was designed specifically for Kotlin to support its unique features like coroutines, extension functions, and final classes. Older Java mocking tools struggled with Kotlin's final classes and suspend functions. MockK uses modern bytecode techniques to overcome these limits, providing a Kotlin-friendly API that feels natural. This design choice makes mocking seamless and powerful for Kotlin developers.
┌───────────────┐
│ Your Test     │
│ Code          │
└──────┬────────┘
       │ Calls
       ▼
┌───────────────┐
│ MockK Proxy   │
│ (Intercepts)  │
└──────┬────────┘
       │ Checks behavior
       ▼
┌───────────────┐
│ Behavior Map  │
│ (every/returns)│
└──────┬────────┘
       │ Returns mocked data
       ▼
┌───────────────┐
│ Records Calls │
│ (for verify)  │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do mocks execute real code by default? Commit to yes or no.
Common Belief:Mocks run the real code unless told otherwise.
Tap to reveal reality
Reality:Mocks do not run real code unless explicitly configured to call real methods.
Why it matters:Assuming mocks run real code can cause tests to fail unexpectedly or run slowly.
Quick: Can you mock final classes with any mocking library? Commit to yes or no.
Common Belief:All mocking libraries can mock any class, including final ones.
Tap to reveal reality
Reality:Many mocking libraries cannot mock Kotlin final classes, but MockK can using bytecode tricks.
Why it matters:Choosing the wrong mocking tool can block testing of important parts of Kotlin apps.
Quick: Does mocking suspend functions work the same as regular functions? Commit to yes or no.
Common Belief:You mock suspend functions the same way as normal functions.
Tap to reveal reality
Reality:Suspend functions require special coroutine-aware mocking methods like coEvery and coVerify.
Why it matters:Using wrong mocking methods for suspend functions leads to test failures or hangs.
Quick: Does verify check how many times a function was called by default? Commit to yes or no.
Common Belief:verify always checks the exact number of calls automatically.
Tap to reveal reality
Reality:verify only checks that a call happened at least once unless you specify call count explicitly.
Why it matters:Misunderstanding verify can cause tests to miss bugs where functions are called too often or too few times.
Expert Zone
1
MockK supports mocking extension functions and top-level functions, which many other libraries cannot do easily.
2
Relaxed mocks can hide missing behavior definitions, so use them carefully to avoid false positives in tests.
3
MockK allows partial mocking (spying) on real objects, letting you mock some methods while keeping others real.
When NOT to use
Avoid using MockK for UI testing or integration tests where real components must interact. Instead, use Espresso or UI Automator for UI, and real test servers or databases for integration. MockK is best suited for unit tests focusing on isolated logic.
Production Patterns
In production Android projects, MockK is used to mock repositories, network clients, and database DAOs during unit tests. Teams often combine MockK with JUnit and coroutine test libraries to write fast, reliable tests that run on the JVM without Android dependencies.
Connections
Dependency Injection
MockK works well with dependency injection by allowing easy replacement of dependencies with mocks.
Understanding dependency injection helps you design code that is easier to mock and test with MockK.
Test-Driven Development (TDD)
MockK enables TDD by letting you write tests that define expected interactions before implementation.
Knowing how MockK supports TDD improves your ability to write clean, testable code from the start.
Theatre Rehearsal
Both involve stand-ins to simulate real actors or components for practice or testing.
Seeing mocking as rehearsal clarifies why controlled, predictable behavior is essential before the real performance.
Common Pitfalls
#1Mock returns null by default causing NullPointerException.
Wrong approach:val mockObj = mockk() every { mockObj.getName() } returns null // Test crashes with NPE
Correct approach:val mockObj = mockk(relaxed = true) // relaxed mocks return default values like empty strings or zeros
Root cause:Mocks are strict by default and return null for non-primitive types unless told otherwise.
#2Using every instead of coEvery for suspend functions causes test hangs.
Wrong approach:every { mockObj.suspendFunction() } returns "Data"
Correct approach:coEvery { mockObj.suspendFunction() } returns "Data"
Root cause:Suspend functions require coroutine-aware mocking methods to work properly.
#3Verifying calls without specifying call count misses multiple calls bug.
Wrong approach:verify { mockObj.method() } // passes if called once or more
Correct approach:verify(exactly = 2) { mockObj.method() } // checks method called exactly twice
Root cause:Default verify only checks if call happened at least once, not how many times.
Key Takeaways
MockK is a Kotlin-friendly mocking library that helps isolate code for reliable unit testing.
You must define mock behavior explicitly using every or coEvery to control test scenarios.
Verifying calls ensures your code interacts correctly with dependencies, catching logic errors.
MockK supports advanced features like mocking final classes, coroutines, and singletons.
Using MockK effectively speeds up development and improves code quality by enabling thorough testing.