Mocking with MockK in Kotlin - Time & Space Complexity
When using MockK to create mocks in Kotlin tests, it's helpful to understand how the time to run tests grows as mocks and calls increase.
We want to see how the number of mocked calls affects the test execution time.
Analyze the time complexity of this simple mocking setup and verification.
import io.mockk.mockk
import io.mockk.verify
fun testMockCalls(n: Int) {
val mock = mockk>()
for (i in 1..n) {
verify(exactly = 0) { mock[i] }
}
}
This code creates a mock list and verifies calls to its get method n times.
Look at what repeats as input grows.
- Primary operation: The for-loop runs verify n times.
- How many times: Exactly n times, once per loop iteration.
As n grows, the number of verify calls grows the same way.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 verify calls |
| 100 | 100 verify calls |
| 1000 | 1000 verify calls |
Pattern observation: The work grows directly with n, so doubling n doubles the operations.
Time Complexity: O(n)
This means the time to run the test grows in a straight line as the number of mocked calls increases.
[X] Wrong: "Mocking and verifying calls always take constant time no matter how many calls there are."
[OK] Correct: Each verify call checks the mock's history, so more calls mean more work, making time grow with n.
Understanding how mocking affects test time helps you write efficient tests and shows you know how code scales, a useful skill in real projects.
"What if we verified all calls once after the loop instead of inside it? How would the time complexity change?"
Practice
Solution
Step 1: Understand mocking concept
Mocking means creating fake versions of objects to test code without using real dependencies.Step 2: Identify MockK's role
MockK is a Kotlin library that helps create these fake objects easily for testing purposes.Final Answer:
To create fake objects that simulate real ones for testing -> Option AQuick Check:
MockK = mocking tool for fake objects [OK]
- Confusing MockK with build or deployment tools
- Thinking MockK is for UI design
- Assuming MockK speeds up compilation
MyService using MockK?Solution
Step 1: Recall MockK syntax for mocking
MockK uses the functionmockk<ClassName>()to create mocks.Step 2: Check each option
val mock = mockk<MyService>() usesmockk<MyService>(), which is correct syntax. Others are invalid or not MockK functions.Final Answer:
val mock = mockk<MyService>() -> Option CQuick Check:
mockk<Class>() creates mock [OK]
- Using uppercase 'MockK' as a function
- Trying to use 'new' keyword in Kotlin
- Using non-existent functions like createMock
val mock = mockk<Calculator>()
every { mock.add(2, 3) } returns 10
println(mock.add(2, 3))
println(mock.add(1, 1))Solution
Step 1: Understand mocking behavior setup
The mock is told to return 10 whenadd(2, 3)is called.Step 2: Check calls and outputs
Callingmock.add(2, 3)returns 10 as set. Callingmock.add(1, 1)has no behavior defined, so MockK throws an exception by default.Final Answer:
10 Exception -> Option AQuick Check:
Defined call returns 10; undefined call throws exception [OK]
- Assuming undefined calls return 0 or null
- Thinking all calls return the same mocked value
- Ignoring that MockK throws exceptions on undefined calls
val mock = mockk<UserRepository>()
every { mock.getUser(any()) } returns User("Alice")
mock.getUser(1)
verify { mock.getUser(1) }Solution
Step 1: Analyze mocking and stubbing
The mock is created normally, andeverysets behavior for any argument usingany(), which is valid.Step 2: Check verification usage
After callingmock.getUser(1), theverifyblock correctly checks that the method was called with argument 1.Final Answer:
No error; code is correct -> Option BQuick Check:
any() matcher and verify block used correctly [OK]
- Thinking relaxed=true is always required
- Confusing verify usage with unnecessary calls
- Misusing any() matcher outside stubbing
PaymentProcessor so that calling process(amount) returns "Success" only when amount is greater than 100, otherwise throws an exception. Which MockK setup achieves this?Solution
Step 1: Understand conditional mocking with matchers
MockK supports argument matchers likegt()(greater than) andltEq()(less than or equal) for conditions.Step 2: Evaluate options for correct matcher usage
every { mock.process(gt(100)) } returns "Success" every { mock.process(ltEq(100)) } throws IllegalArgumentException() correctly usesgt(100)to return "Success" andltEq(100)to throw exception, matching the requirement precisely.Final Answer:
every { mock.process(gt(100)) } returns "Success" every { mock.process(ltEq(100)) } throws IllegalArgumentException() -> Option DQuick Check:
Use gt() and ltEq() for conditional mocking [OK]
- Using match { } lambda instead of built-in matchers
- Mocking only specific values, missing ranges
- Returning success for all inputs ignoring conditions
Ready to prove it?
Pass the test and this pattern moves unknown
