MockK: Was ist das, Schlüsselkonzepte und Syntax

Autor: IT Sectr Veröffentlicht: 2026-04-08 Lesezeit: 8 Min.

MockK ist ein Kotlin-first Framework zum Erstellen von Mock-Objekten, das speziell für das Kotlin-Ökosystem unter Berücksichtigung seiner Sprachmerkmale entwickelt wurde: Koroutinen, Erweiterungsfunktionen, data class und sealed class. Im Gegensatz zu Mockito, das von Java nach Kotlin portiert wurde, wurde MockK von Grund auf für die Kotlin-Syntax entwickelt und benötigt keine zusätzlichen Plugins für die Arbeit mit final-Klassen. Laut MockK.io wird die Bibliothek in mehr als 40% der Kotlin-Projekte mit Komponententests eingesetzt.

Wichtige Punkte

  • MockK — eine Kotlin-orientierte Mocking-Bibliothek mit Unterstützung für Koroutinen und Sprachfunktionen.
  • mockk() — die Hauptmethode zum Erstellen eines Mock-Objekts, ähnlich wie Mockito.mock().
  • every { } — ein Block zum Konfigurieren des Mock-Verhaltens (Stubbing) im deklarativen Stil.
  • coEvery / coVerify — spezielle Konstrukte für die Arbeit mit suspend-Funktionen von Koroutinen.
  • Relaxed mock — ein Mock, der ohne explizites Stubbing Standardwerte zurückgibt.

Was ist MockK?

MockK ist eine Bibliothek zum Erstellen von Mock-Objekten, die in Kotlin geschrieben und für dessen Syntax optimiert ist. Sie löst dieselben Probleme wie Mockito — Isolation des getesteten Codes von Abhängigkeiten — aber tut dies mit Kotlin-spezifischen Konstrukten: Lambdas, DSL, reified Generics und suspend-Funktionen.

Der Hauptvorteil von MockK gegenüber portierten Lösungen ist die native Kotlin-Unterstützung. In Mockito erfordert das Mocken einer final-Klasse opt-in (mockito-inline) und statische Methoden benötigen mockStatic. MockK unterstützt dies standardmäßig, da Kotlin-Klassen standardmäßig final sind und die Umgehung dieser Einschränkung in die Architektur der Bibliothek integriert ist.

Version 1.13.12 (2024) ist eine stabile Version, die Kotlin 2.0, den K2-Compiler und plattformübergreifende Projekte (KMP) unterstützt. MockK funktioniert auch mit Kotlin/Native und Kotlin/JS, was es zur einzigen Wahl für KMP-Projekte macht, bei denen weder Mockito noch EasyMock anwendbar sind.

MockK ist unter Berücksichtigung der Besonderheiten von Kotlin konzipiert und nutzt Sprachfunktionen — reified Generics, DSL mit Lambdas, Inline-Funktionen — um eine präzise und typsichere API ohne Leistungseinbußen zu bieten.

Wie MockK funktioniert

Der Mechanismus von MockK basiert auf Bytecode-Instrumentierung durch die Bibliothek ByteBuddy (wie Mockito), verpackt sie jedoch in ein Kotlin-freundliches DSL. Anstelle von when().thenReturn()-Ketten verwendet MockK Lambda-Blöcke every { } und coEvery { }, die wie eine natürliche Erweiterung der Sprache aussehen. Unter der Haube fängt MockK den Aufruf innerhalb des Lambdas ab, analysiert Methode und Argumente durch Reflektion und gleicht sie mit den aufgezeichneten Stubbing-Regeln ab.

Grundlegende MockK-Syntax

Der Block every { mock.method() } returns value wird gelesen als „jedes Mal, wenn die Methode aufgerufen wird, gib den Wert zurück.“ Diese deklarative Syntax ist näher am Kotlin-Stil und beseitigt Verwirrung über die Argumentreihenfolge in when(). Dank Kotlins reified Generics wird der Mock-Typ automatisch abgeleitet, ohne die Klasse explizit angeben zu müssen.

kotlin
val repository = mockk<UserRepository>()

// Stubbing: Jeder Aufruf von findById(1) gibt den Benutzer zurück
every { repository.findById(1) } returns User("Alice")

// Aufruf und Überprüfung
val result = repository.findById(1)
assertEquals("Alice", result.name)

Relaxed Mock: Weniger Boilerplate

Im Gegensatz zu Mockito, wo jede Methode explizit konfiguriert werden muss, unterstützt MockK relaxed mock — einen Mock, der für jede Methode „vernünftige“ Standardwerte zurückgibt: eine leere Liste für List, 0 für Int, einen leeren String für String. Dies reduziert die Menge an Setup-Code drastisch.

kotlin
// Relaxed mock — alle Methoden geben Standardwerte zurück
val api = mockk<ApiService>(relaxed = true)

// Kein Stubbing erforderlich — gibt eine leere Liste zurück
println(api.getUsers()) // []

Erstellen von Mocks und relaxierten Mocks

MockK bietet mehrere Möglichkeiten zum Erstellen von Mock-Objekten: mockk<T>() für strenge Mocks (jede Methode muss explizit konfiguriert werden), mockk<T>(relaxed = true) für relaxierte Mocks und spyk(obj) zum Erstellen eines Spions auf einem realen Objekt.

FunktionTypVerhalten ohne Stubbing
mockk()Strenge MockWirft Ausnahme beim Aufruf einer nicht gestubten Methode
mockk(relaxed = true)Relaxierte MockGibt Standardwert zurück
spyk()SpionRuft die echte Methode auf, wenn kein Stub konfiguriert ist
slot()Argument CaptorErfasst das Argument zur Überprüfung

Die Wahl zwischen strengem und relaxiertem Mock hängt vom Kontext ab. Ein strenger Mock stellt sicher, dass der Test keine Methoden verwendet, deren Verhalten nicht definiert ist — das erhöht die Zuverlässigkeit. Ein relaxierter Mock ist praktisch für schnelles Test-Prototyping, bei dem nicht alle Abhängigkeiten wichtig sind. In der Praxis wird empfohlen, mit einem strengen Mock zu beginnen und nur dann auf relaxiert umzusteigen, wenn das Stubbing mehr Zeilen beansprucht als der Test selbst.

Stubbing: Verhalten mit dem every-Block konfigurieren

Der every-Block ist das zentrale Stubbing-Konstrukt in MockK. Innerhalb des Lambdas wird ein Methodenaufruf mit bestimmten Argumenten beschrieben, und dann wird ein Wert über returns zurückgegeben, eine Ausnahme über throws geworfen oder eine Antwort über answers berechnet.

Verschiedene Stubbing-Methoden

MockK unterstützt alle für Tests erforderlichen Szenarien: Rückgabe eines Werts, Auslösen einer Ausnahme, Berechnen einer Antwort basierend auf Argumenten und mehrere Antworten in Reihenfolge (Aufrufsequenz).

kotlin
// Wert zurückgeben
every { repo.findById(1) } returns User("Alice")

// Ausnahme werfen
every { repo.findById(999) } throws NotFoundException()

// Dynamische Antwort
every { repo.save(any()) } answers {
    val user = firstArg<User>()
    user.copy(id = 42)
}

// Antwortsequenz
every { repo.findAll() } returnsMany listOf(
    listOf(User("Alice")),
    listOf(User("Bob")),
    emptyList()
)

Verify und coVerify für Koroutinen

Verify in MockK ist im Zweck ähnlich wie Mockito.verify(), verwendet aber Kotlin-DSL: verify { mock.method() }. Für suspend-Funktionen wird coVerify { mock.suspendMethod() } verwendet, das korrekt mit Koroutinen funktioniert und keinen speziellen Runner benötigt.

Überprüfung der Aufrufanzahl

MockK unterstützt dieselben Modifikatoren wie Mockito: exactly(1), atLeast(2), atMost(5), wasNot(Called). Die Syntax ist minimalistisch — der Modifikator wird als erstes Argument in verify { } übergeben.

kotlin
// Überprüfung: Methode wurde genau 1 Mal aufgerufen
verify(exactly = 1) { repo.save(any()) }

// Aufrufreihenfolge überprüfen
verifySequence {
    repo.save(any())
    repo.flush()
}

// coVerify für suspend-Funktionen
coVerify { api.fetchUsers() }

Slot: Argumente erfassen

Zur Argumentüberprüfung wird slot() verwendet — ein Analogon zu ArgumentCaptor. Ein Slot wird vor dem Aufruf deklariert, an every oder verify übergeben und enthält nach der Testausführung den erfassten Wert.

kotlin
val userSlot = slot<User>()

verify { repo.save(capture(userSlot)) }

assertEquals("Alice", userSlot.captured.name)

MockK-Annotationen und JUnit-Integration

MockK bietet die Annotationen @MockK und @RelaxedMockK zum Erstellen von Mocks durch Initialisierung in JUnit 5. Die Erweiterung MockKExtension erstellt automatisch Mocks vor jedem Test und räumt danach auf — ähnlich wie MockitoExtension, aber mit Unterstützung für den relaxierten Modus.

Beispiel mit MockKExtension

Die Annotation @InjectMockKs (oder die Alternative @MockK mit expliziter Objekterstellung) injiziert Mocks in die getestete Instanz. Dies reduziert Boilerplate und macht den Testcode sauberer.

kotlin
@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)
    }
}

MockK vs Mockito: Was für Kotlin wählen

Die Wahl zwischen MockK und Mockito hängt von der Teamzusammensetzung und dem Projekttyp ab. Mockito hat ein größeres Ökosystem, mehr Beispiele und Integrationen, aber MockK bietet eine sauberere Kotlin-Syntax und native Unterstützung für Sprachfunktionen. Für neue Kotlin-Projekte wird MockK als idiomatischere Lösung empfohlen.

KriteriumMockKMockito
SyntaxKotlin DSL (every, verify)Java-Stil (when, thenReturn)
KoroutinencoEvery, coVerify (nativ)Erfordert zusätzliche Bibliotheken
Final-KlasseStandardmäßig unterstütztErfordert mockito-inline
KMPUnterstütztNicht unterstützt
Relaxed mockIntegriertKein Äquivalent
BeliebtheitWachsend in der Kotlin-CommunityDominiert in Java- und Hybrid-Projekten

Für reine Kotlin-Projekte (ohne Java-Klassen) ist MockK vorzuziehen: weniger Boilerplate, native Koroutinen-Unterstützung, keine Überraschungen mit final-Klassen. Für Hybrid-Projekte oder Teams mit Java-Hintergrund bleibt Mockito eine funktionierende Option — beide Bibliotheken können über verschiedene Module im selben Projekt verwendet werden. Bei der Migration von Mockito zu MockK reicht es aus, die @Mock-Annotationen durch @MockK zu ersetzen und when().thenReturn()-Blöcke in das every { }-Format umzuschreiben.

Häufig gestellte Fragen

Wie unterscheidet sich ein relaxierter Mock von einem normalen Mock in MockK?

Relaxed mock gibt für alle nicht gestubten Methoden Standardwerte (leere Liste, 0, null) zurück, ohne Ausnahmen zu werfen. Ein normaler (strenger) Mock erfordert explizites Stubbing jeder Methode — andernfalls schlägt der Test fehl. Relaxierter Mock ist praktisch für schnelle Tests, strenger für zuverlässige Tests.

Wie mockt man Erweiterungsfunktionen in MockK?

MockK unterstützt das Mocken von Erweiterungsfunktionen über mockkStatic(). Dies ist möglich, weil Erweiterungsfunktionen in Kotlin statische Methoden mit dem Empfänger als erstem Parameter sind. Für jede Erweiterungsfunktion müssen Sie die Klasse angeben, in der sie deklariert ist.

Funktioniert MockK mit Kotlin Multiplatform?

Ja, MockK unterstützt Kotlin Multiplatform (KMP) für gemeinsamen Code. Auf JVM-, Native- und JS-Plattformen können Sie die gemeinsame API verwenden: mockk(), every, verify. Dies macht MockK zur einzigen Wahl für KMP-Projekte, bei denen Mockito nicht funktioniert.

Wie überprüft man die Aufrufreihenfolge in MockK?

Verwenden Sie verifySequence { } — einen Block, in dem Aufrufe streng in der erwarteten Reihenfolge angegeben werden. Wenn die tatsächliche Reihenfolge abweicht, wirft verifySequence eine Ausnahme, die den ersten nicht übereinstimmenden Aufruf angibt.

Können MockK und Mockito im selben Projekt verwendet werden?

Ja, technisch ist es möglich, aber nicht empfohlen. Konflikte können auf der Ebene der Bytecode-Instrumentierung auftreten (ByteBuddy vs mockito-inline). Wenn ein Projekt bereits Mockito verwendet, kann die Migration zu MockK schrittweise durch Modulisolierung erfolgen.

Zusammenfassung

  • MockK — eine Kotlin-first Mocking-Bibliothek mit nativer Sprachunterstützung.
  • every { } — ein deklaratives DSL zum Konfigurieren des Mock-Verhaltens.
  • coEvery / coVerify — Unterstützung für suspend-Funktionen in Koroutinen ohne zusätzliche Abhängigkeiten.
  • Relaxed mock — ein Mock mit Standardwerten, der Boilerplate reduziert.
  • @MockK / @InjectMockKs — Annotationen zur automatischen Mock-Erstellung in JUnit 5.
  • MockK vs Mockito — MockK ist für reine Kotlin-Projekte und KMP zu bevorzugen.
  • verifySequence — Überprüfung der strengen Reihenfolge von Methodenaufrufen.

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch