Unit Testing & MockK Quiz
TESTING › Unit
Which annotation pair correctly sets up a strict MockK mock and ensures it is initialized?
- @Mock with Mockito.openMocks()
- @MockK with MockKAnnotations.init(this)
- @RelaxedMockK with no initialization needed
- @InjectMockKs with @Before { } only
Answer: @MockK with MockKAnnotations.init(this)
MockK uses @MockK for a strict mock, and the fields must be initialized via MockKAnnotations.init(this) (often in @Before) or the MockK JUnit extension. @Mock/openMocks belong to Mockito.
You want a unit test where an unstubbed call to a collaborator returns a default value instead of throwing. What is the most direct MockK approach?
- Wrap each collaborator call in try/catch blocks instead
- Use spyk(RealImpl()) so the real implementation handles it
- Create the mock with mockk(relaxed = true) from the start
- Call confirmVerified() first to force default return values
Answer: Create the mock with mockk(relaxed = true) from the start
A relaxed mock returns sensible defaults for any call you did not explicitly stub, so unstubbed calls do not throw. spyk runs real code, and confirmVerified only checks verification.
What is the idiomatic way to test a ViewModel function that calls a suspend repository method?
- Block the main thread with Thread.sleep until it finishes
- Use coEvery to stub and coVerify inside runTest
- Mark the test method itself as suspend
- Use every/verify exactly as with non-suspend functions
Answer: Use coEvery to stub and coVerify inside runTest
Suspend functions require MockK's coEvery/coVerify, executed inside runTest so coroutines run on the test scheduler. Plain every/verify cannot stub suspend calls, and JUnit test methods cannot be suspend.
According to Android's testing guidance, which test double should you generally prefer for a repository interface you own?
- A hand-written fake with simple in-memory behavior
- A mock that checks every method call and its exact order
- A spy around the production code that watches each call
- A dummy object that is passed in but never actually used
Answer: A hand-written fake with simple in-memory behavior
Google recommends fakes for collaborators you control: a fake has real, simplified behavior, making tests less brittle than interaction-heavy mocks that couple tests to implementation details.
Which JUnit annotation runs setup code before each individual @Test method?
- @BeforeClass
- @Rule
- @Before
- @Setup
Answer: @Before
@Before runs before every test method, giving each test a fresh fixture. @BeforeClass runs once for the whole class (and must be static), and @Setup is not a JUnit annotation.
You need to assert that the exact object passed into mock.save() has a specific field value. Which MockK feature fits best?
- verifyOrder { } to check the ordering of calls across mocks
- andThen chaining to script a sequence of return values
- mockkStatic() for mocking top-level or static functions
- A slot<T>() with capture(), then read slot.captured
Answer: A slot<T>() with capture(), then read slot.captured
A CapturingSlot created with slot<T>() and wired via capture() records the actual argument, which you then inspect through slot.captured. The other options control ordering, sequential return values, or static mocking.
Which of these is the WEAKEST candidate for a JVM unit test?
- A pure function that computes a discount from cart state
- A state reducer that maps events directly to UI state
- A trivial getter returning its backing field unchanged
- Edge-case parsing that handles malformed input safely
Answer: A trivial getter returning its backing field unchanged
Trivial getters with no logic have no behavior of yours to verify, so a test just restates the implementation. Business logic, state transformations, and edge cases are exactly what unit tests should cover.
What distinguishes verifySequence from verifyOrder in MockK?
- verifyOrder fails if any unlisted call also happens on the mock during verification
- Both work the same way, but they only succeed when the mock is relaxed and fully stubbed
- verifySequence is strict: only the listed calls in order, with no extras on the mock
- verifyOrder ignores call order and only checks that the requested calls happened somehow
Answer: verifySequence is strict: only the listed calls in order, with no extras on the mock
verifySequence demands the exact set of calls in the given order with nothing else on the mock, while verifyOrder only checks the listed calls occurred in that relative order and tolerates other interleaved calls.
A ViewModel launches work in viewModelScope, which uses Dispatchers.Main. What lets this run in a plain JVM unit test?
- Swap Main via Dispatchers.setMain, usually a MainDispatcherRule
- Move the test into src/androidTest so a real Looper is available
- Insert a Thread.sleep after the call so Main can finish first
- Annotate the ViewModel with @VisibleForTesting so Main is skipped
Answer: Swap Main via Dispatchers.setMain, usually a MainDispatcherRule
Dispatchers.Main is not available on a bare JVM, so kotlinx-coroutines-test's Dispatchers.setMain (often wrapped in a MainDispatcherRule) swaps in a controllable test dispatcher. Sleeping or moving to androidTest defeats the point of a fast unit test.
You need a mocked method to return 1 on its first invocation and 2 on its second. Which MockK stub is correct?
- Two separate every { m.next() } returns ... blocks, since the first one wins on call one
- coEvery { m.next() } returns listOf(1, 2)
- every { m.next() } returns Pair(1, 2)
- every { m.next() } returns 1 andThen 2
Answer: every { m.next() } returns 1 andThen 2
Chaining returns with andThen supplies sequential results across successive calls (returnsMany also works). A second every block just overrides the first, and the other options return the wrong type rather than a sequence.
What does the @InjectMockKs annotation do in a MockK-based test?
- It marks the field as a relaxed mock that returns default values
- It builds the class under test and injects the mock fields into it
- It replaces MockKAnnotations.init and auto-initializes all annotations
- It wires Hilt-provided dependencies into the test class for you
Answer: It builds the class under test and injects the mock fields into it
@InjectMockKs builds the subject-under-test and injects the declared mock fields into its constructor or properties, so you do not assemble the object by hand. It still requires the mocks to be initialized first.
In a standard Android module, which source set holds fast JVM unit tests that need no device?
- src/androidTest
- src/main
- src/debug
- src/test
Answer: src/test
Local unit tests live in src/test and run on the host JVM. src/androidTest holds instrumented tests that require a device or emulator, and src/main and src/debug are production source sets.
What is the idiomatic Kotlin way to assert that calling a function throws IllegalArgumentException?
- assertFailsWith<IllegalArgumentException> { subject.run() }
- Wrap the call in try/catch and let the test pass if nothing is printed
- Annotate the method with @Test(timeout = 0)
- verify { subject.run() } and check the return value is null
Answer: assertFailsWith<IllegalArgumentException> { subject.run() }
assertFailsWith<T> (or JUnit's assertThrows) runs the block, fails if no exception is thrown, fails if the wrong type is thrown, and returns the exception for further assertions. A bare try/catch can pass even when nothing throws.
You wrap a real object with spyk(RealService()) and never stub its foo() method. What happens when the test calls foo()?
- It throws a MockKException because foo() was never stubbed
- It runs the real foo() implementation on the wrapped object
- It returns a default value like null or 0 from a relaxed mock
- It records the call but skips the method body on the spy
Answer: It runs the real foo() implementation on the wrapped object
A spy delegates unstubbed calls to the real underlying object, so foo() runs for real while you can still stub or verify selected methods. A plain mockk would throw or, if relaxed, return defaults instead.