MockK — is een Kotlin-first framework voor het maken van mock-objecten, speciaal ontworpen voor het Kotlin-ecosysteem met inachtneming van zijn taalkenmerken: coroutines, extensiefuncties, data class en sealed class. In tegenstelling tot Mockito, dat vanuit Java naar Kotlin is gepoort, is MockK vanaf het begin ontworpen voor Kotlin-syntaxis en heeft het geen extra plug-ins nodig om met final-klassen te werken. Volgens gegevens van MockK.io wordt de bibliotheek gebruikt in meer dan 40% van de Kotlin-projecten met modulair testen.
Belangrijkste punten
MockK — is een bibliotheek voor het maken van mock-objecten, geschreven in Kotlin en geoptimaliseerd voor de syntaxis ervan. Het lost dezelfde taken op als Mockito — isolatie van geteste code van afhankelijkheden — maar doet dit met behulp van Kotlin-specifieke constructies: lambda's, DSL, reified generics en suspend-functies.
Het belangrijkste voordeel van MockK ten opzichte van geporte oplossingen — native ondersteuning voor Kotlin. In Mockito vereist het mocken van een final-klasse opt-in (mockito-inline) en statische methoden vereisen mockStatic. MockK ondersteunt dit standaard, omdat Kotlin-klassen standaard final zijn en het omzeilen van deze beperking is ingebouwd in de architectuur van de bibliotheek.
Versie 1.13.12 (2024) — een stabiele release die Kotlin 2.0, K2-compiler en multiplatform-projecten (KMP) ondersteunt. MockK werkt ook met Kotlin/Native en Kotlin/JS, waardoor het de enige keuze is voor KMP-projecten waar noch Mockito noch EasyMock toepasbaar zijn.
MockK is ontworpen met het oog op de specificiteit van Kotlin en maakt gebruik van taalcapaciteiten — reified generics, DSL met lambda's, inline-functies — om een beknopte en typeveilige API te bieden zonder prestatieverlies.
Mechanisme MockK is gebaseerd op bytecode-instrumentatie via de bibliotheek ByteBuddy (net als Mockito), maar verpakt het in een Kotlin-vriendelijke DSL. In plaats van ketens when().thenReturn() gebruikt MockK lambda-blokken every { } en coEvery { }, die eruitzien als een natuurlijke uitbreiding van de taal. Onder de motorkap onderschept MockK de aanroep binnen de lambda, analyseert de methode en argumenten via reflectie en matcht ze met geregistreerde stubbing-regels.
Het blok every { mock.method() } returns value wordt gelezen als “wanneer de methode wordt aangeroepen, retourneer de waarde”. Een dergelijke declaratieve syntaxis ligt dichter bij de Kotlin-stijl en elimineert verwarring met de volgorde van argumenten in when(). Dankzij reified generics in Kotlin wordt het type mock automatisch afgeleid zonder expliciete klasse-specificatie.
val repository = mockk<UserRepository>()
// Stubbing: elke aanroep findById(1) retourneert de gebruiker
every { repository.findById(1) } returns User("Alice")
// Aanroep en verificatie
val result = repository.findById(1)
assertEquals("Alice", result.name)
In tegenstelling tot Mockito, waar elke methode expliciet moet worden geconfigureerd, ondersteunt MockK relaxed mock — een mock die “redelijke” standaardwaarden retourneert voor elke methode: een lege lijst voor List, 0 voor Int, een lege string voor String. Dit vermindert de hoeveelheid voorbereidende code drastisch.
// Relaxed mock — alle methoden retourneren standaardwaarden
val api = mockk<ApiService>(relaxed = true)
// Vereist geen stubbing — retourneert lege lijst
println(api.getUsers()) // []
MockK biedt verschillende manieren om mock-objecten te maken: mockk<T>() voor een strikte mock (elke methode moet expliciet worden geconfigureerd), mockk<T>(relaxed = true) voor een ontspannen mock en spyk(obj) voor het maken van een spy op een echt object.
| Functie | Type | Gedrag zonder stubbing |
|---|---|---|
| mockk() | Strikte mock | Gooit uitzondering bij aanroep van niet-gestubde methode |
| mockk(relaxed = true) | Ontspannen mock | Retourneert standaardwaarde |
| spyk() | Spy | Roept echte methode aan als stub niet is geconfigureerd |
| slot() | Argument Captor | Vangt argument voor verificatie |
De keuze tussen een strikte en ontspannen mock hangt af van de context. Een strikte mock garandeert dat de test geen methoden gebruikt waarvan het gedrag niet is gedefinieerd — dit verhoogt de betrouwbaarheid. Een ontspannen mock is handig voor snel prototypen van tests waar niet alle afhankelijkheden belangrijk zijn. In de praktijk wordt aanbevolen om met een strikte mock te beginnen en alleen over te schakelen naar relaxed wanneer stubbing meer regels inneemt dan de test zelf.
Het every-blok — is de centrale constructie van stubbing in MockK. Binnen de lambda wordt een methodeaanroep met specifieke argumenten beschreven, waarna de waarde wordt geretourneerd via returns, een uitzondering wordt gegooid via throws of een antwoord wordt berekend via answers.
MockK ondersteunt alle scenario's die nodig zijn voor testen: waarde retourneren, uitzondering gooien, antwoord berekenen op basis van argumenten, meerdere antwoorden op volgorde (sequentie van aanroepen).
// Waarde retourneren
every { repo.findById(1) } returns User("Alice")
// Uitzondering gooien
every { repo.findById(999) } throws NotFoundException()
// Dynamisch antwoord
every { repo.save(any()) } answers {
val user = firstArg<User>()
user.copy(id = 42)
}
// Antwoordsequentie
every { repo.findAll() } returnsMany listOf(
listOf(User("Alice")),
listOf(User("Bob")),
emptyList()
)
Verify in MockK is qua betekenis analoog aan Mockito.verify() maar gebruikt Kotlin DSL: verify { mock.method() }. Voor suspend-functies wordt coVerify { mock.suspendMethod() } gebruikt, dat correct werkt met coroutines en geen speciale runner vereist.
MockK ondersteunt dezelfde modificatoren als Mockito: exactly(1), atLeast(2), atMost(5), wasNot(Called). De syntaxis is minimalistisch — de modificator wordt als eerste argument in verify { } doorgegeven.
// Verificatie: methode precies 1 keer aangeroepen
verify(exactly = 1) { repo.save(any()) }
// Volgorde van aanroepen controleren
verifySequence {
repo.save(any())
repo.flush()
}
// coVerify voor suspend-functies
coVerify { api.fetchUsers() }
Voor het controleren van argumenten wordt slot() gebruikt — de analogie van ArgumentCaptor. De slot wordt vlak voor de aanroep gedeclareerd, doorgegeven aan every of verify, en bevat na uitvoering van de test de vastgelegde waarde.
val userSlot = slot<User>()
verify { repo.save(capture(userSlot)) }
assertEquals("Alice", userSlot.captured.name)
MockK biedt annotaties @MockK en @RelaxedMockK voor het maken van mocks via initialisatie in JUnit 5. De extensie MockKExtension maakt automatisch mocks aan voor elke test en ruimt daarna op — vergelijkbaar met MockitoExtension, maar met ondersteuning voor de relaxed-modus.
De annotatie @InjectMockKs (of het alternatief @MockK met expliciete objectcreatie) injecteert mocks in de geteste instantie. Dit vermindert boilerplate en maakt de testcode schoner.
@ExtendWith(MockKExtension::class)
class UserServiceTest {
@MockK
lateinit var repository: UserRepository
@InjectMockKs
lateinit var service: UserService
@Test
fun `getUser returns user from repository`() {
every { repository.findById(1) } returns User("Alice")
assertEquals("Alice", service.getUser(1)?.name)
}
}
De keuze tussen MockK en Mockito hangt af van de teamsamenstelling en het projecttype. Mockito heeft een groter ecosysteem, meer voorbeelden en integraties, maar MockK biedt een schonere Kotlin-syntaxis en native ondersteuning voor taalfuncties. Voor nieuwe Kotlin-projecten wordt MockK aanbevolen als de meer idiomatische oplossing.
| Criterium | MockK | Mockito |
|---|---|---|
| Syntaxis | Kotlin DSL (every, verify) | Java-stijl (when, thenReturn) |
| Coroutines | coEvery, coVerify (natively) | Vereist extra bibliotheken |
| Final class | Standaard ondersteund | Vereist mockito-inline |
| KMP | Ondersteund | Niet ondersteund |
| Relaxed mock | Ingebouwd | Geen equivalent |
| Populariteit | Groeiend in Kotlin-gemeenschap | Domineert in Java en hybride projecten |
Voor projecten in puur Kotlin (zonder Java-klassen) verdient MockK de voorkeur: minder boilerplate, native ondersteuning voor coroutines, geen verrassingen met final-klassen. Voor hybride projecten of teams met Java-achtergrond blijft Mockito een werkende optie — beide bibliotheken kunnen in hetzelfde project via verschillende modules worden gebruikt. Bij migratie van Mockito naar MockK volstaat het om @Mock-annotaties te vervangen door @MockK en when().thenReturn()-blokken te herschrijven naar every { }-formaat.
Veelgestelde vragen
Relaxed mock retourneert standaardwaarden voor alle niet-gestubde methoden (lege lijst, 0, null) zonder uitzonderingen te gooien. Een gewone (strict) mock vereist expliciete stubbing van elke methode — anders faalt de test. Relaxed mock is handig voor snelle tests, strict — voor betrouwbare tests.
MockK ondersteunt het mocken van extensiefuncties via mockkStatic(). Dit is mogelijk omdat extensiefuncties in Kotlin statische methoden zijn met een eerste receptorparameter. Voor elke extensiefunctie moet de klasse worden opgegeven waarin deze is gedeclareerd.
Ja, MockK ondersteunt Kotlin Multiplatform (KMP) voor gemeenschappelijke code. Op de platforms JVM, Native en JS kan de gemeenschappelijke API mockk(), every, verify worden gebruikt. Dit maakt MockK de enige keuze voor KMP-projecten waar Mockito niet werkt.
Gebruik verifySequence { } — een blok waarin aanroepen strikt in de verwachte volgorde worden gespecificeerd. Als de werkelijke volgorde afwijkt, gooit verifySequence een uitzondering met vermelding van de eerste niet-overeenkomende aanroep.
Ja, technisch is het mogelijk, maar niet aanbevolen. Conflicten kunnen optreden op het niveau van bytecode-instrumentatie (ByteBuddy vs mockito-inline). Als het project al Mockito gebruikt, kan de migratie naar MockK geleidelijk verlopen via isolatie van modules.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook