MockK : qu'est-ce que c'est, concepts clés et syntaxe

Auteur : IT Sectr Publié le : 2026-04-08 Temps de lecture : 8 min

MockK est un framework Kotlin-first pour créer des objets mock, conçu spécifiquement pour l'écosystème Kotlin en tenant compte de ses caractéristiques linguistiques : coroutines, fonctions d'extension, data class et sealed class. Contrairement à Mockito, qui a été porté de Java vers Kotlin, MockK a été conçu dès l'origine pour la syntaxe Kotlin et ne nécessite pas de plugins supplémentaires pour fonctionner avec les classes final. Selon MockK.io, la bibliothèque est utilisée dans plus de 40 % des projets Kotlin avec des tests unitaires.

Points clés

  • MockK — une bibliothèque de mocking orientée Kotlin avec prise en charge des coroutines et des fonctionnalités du langage.
  • mockk() — la méthode principale pour créer un objet mock, similaire à Mockito.mock().
  • every { } — un bloc pour configurer le comportement du mock (stubbing) de manière déclarative.
  • coEvery / coVerify — des constructions spéciales pour travailler avec les fonctions suspend des coroutines.
  • Relaxed mock — un mock qui retourne des valeurs par défaut sans stubbing explicite.

Qu'est-ce que MockK ?

MockK est une bibliothèque pour créer des objets mock, écrite en Kotlin et optimisée pour sa syntaxe. Elle résout les mêmes problèmes que Mockito — isoler le code testé des dépendances — mais le fait en utilisant des constructions spécifiques à Kotlin : lambdas, DSL, reified generics et fonctions suspend.

Le principal avantage de MockK par rapport aux solutions portées est la prise en charge native de Kotlin. Dans Mockito, simuler une classe final nécessite un opt-in (mockito-inline), et les méthodes statiques nécessitent mockStatic. MockK le supporte par défaut, car les classes Kotlin sont final par défaut, et contourner cette limitation est intégré dans l'architecture de la bibliothèque.

La version 1.13.12 (2024) est une version stable prenant en charge Kotlin 2.0, le compilateur K2 et les projets multiplateformes (KMP). MockK fonctionne également avec Kotlin/Native et Kotlin/JS, ce qui en fait le seul choix pour les projets KMP où ni Mockito ni EasyMock ne sont applicables.

MockK est conçu en tenant compte des spécificités de Kotlin et utilise les fonctionnalités du langage — reified generics, DSL avec lambdas, fonctions inline — pour fournir une API concise et type-safe sans sacrifier les performances.

Comment fonctionne MockK

Le mécanisme de MockK est basé sur l'instrumentation de bytecode via la bibliothèque ByteBuddy (comme Mockito), mais l'enveloppe dans un DSL compatible Kotlin. Au lieu des chaînes when().thenReturn(), MockK utilise des blocs lambda every { } et coEvery { } qui ressemblent à une extension naturelle du langage. Sous le capot, MockK intercepte l'appel dans le lambda, analyse la méthode et les arguments via la réflexion et les fait correspondre aux règles de stubbing enregistrées.

Syntaxe de base de MockK

Le bloc every { mock.method() } returns value se lit comme « à chaque fois que la méthode est appelée, retourner la valeur. » Cette syntaxe déclarative est plus proche du style Kotlin et élimine la confusion sur l'ordre des arguments dans when(). Grâce aux reified generics de Kotlin, le type du mock est déduit automatiquement sans spécifier explicitement la classe.

kotlin
val repository = mockk<UserRepository>()

// Stubbing : chaque appel à findById(1) retourne l'utilisateur
every { repository.findById(1) } returns User("Alice")

// Appel et vérification
val result = repository.findById(1)
assertEquals("Alice", result.name)

Relaxed mock : moins de code répétitif

Contrairement à Mockito, où chaque méthode doit être configurée explicitement, MockK prend en charge le relaxed mock — un mock qui retourne des valeurs par défaut « raisonnables » pour toute méthode : une liste vide pour List, 0 pour Int, une chaîne vide pour String. Cela réduit considérablement la quantité de code de configuration.

kotlin
// Relaxed mock — toutes les méthodes retournent des valeurs par défaut
val api = mockk<ApiService>(relaxed = true)

// Ne nécessite pas de stubbing — retourne une liste vide
println(api.getUsers()) // []

Création de mocks et de mocks relaxés

MockK propose plusieurs façons de créer des objets mock : mockk<T>() pour les mocks stricts (chaque méthode doit être configurée explicitement), mockk<T>(relaxed = true) pour les mocks relaxés, et spyk(obj) pour créer un espion sur un objet réel.

FonctionTypeComportement sans stubbing
mockk()Mock strictLève une exception lors de l'appel d'une méthode non configurée
mockk(relaxed = true)Mock relaxéRetourne la valeur par défaut
spyk()EspionAppelle la méthode réelle si aucun stub n'est configuré
slot()Argument CaptorCapture l'argument pour vérification

Le choix entre mock strict et relaxé dépend du contexte. Un mock strict garantit que le test n'utilise pas de méthodes dont le comportement n'est pas défini — cela augmente la fiabilité. Un mock relaxé est pratique pour le prototypage rapide de tests où toutes les dépendances ne sont pas importantes. En pratique, il est recommandé de commencer avec un mock strict et de passer au relaxé uniquement lorsque le stubbing prend plus de lignes que le test lui-même.

Stubbing : configuration du comportement avec le bloc every

Le bloc every est la construction centrale de stubbing dans MockK. Dans le lambda, un appel de méthode avec des arguments spécifiques est décrit, puis une valeur est retournée via returns, une exception est levée via throws, ou une réponse est calculée via answers.

Différentes méthodes de stubbing

MockK prend en charge tous les scénarios nécessaires aux tests : retourner une valeur, lever une exception, calculer une réponse basée sur les arguments et plusieurs réponses dans l'ordre (séquence d'appels).

kotlin
// Retourner une valeur
every { repo.findById(1) } returns User("Alice")

// Lever une exception
every { repo.findById(999) } throws NotFoundException()

// Réponse dynamique
every { repo.save(any()) } answers {
    val user = firstArg<User>()
    user.copy(id = 42)
}

// Séquence de réponses
every { repo.findAll() } returnsMany listOf(
    listOf(User("Alice")),
    listOf(User("Bob")),
    emptyList()
)

Verify et coVerify pour les coroutines

Verify dans MockK est similaire à Mockito.verify() dans son but, mais utilise le DSL Kotlin : verify { mock.method() }. Pour les fonctions suspend, on utilise coVerify { mock.suspendMethod() }, qui fonctionne correctement avec les coroutines et ne nécessite pas d'exécuteur spécial.

Vérification du nombre d'appels

MockK prend en charge les mêmes modificateurs que Mockito : exactly(1), atLeast(2), atMost(5), wasNot(Called). La syntaxe est minimaliste — le modificateur est passé comme premier argument dans verify { }.

kotlin
// Vérification : méthode appelée exactement 1 fois
verify(exactly = 1) { repo.save(any()) }

// Vérifier l'ordre des appels
verifySequence {
    repo.save(any())
    repo.flush()
}

// coVerify pour les fonctions suspend
coVerify { api.fetchUsers() }

Slot : capture d'arguments

Pour la vérification des arguments, on utilise slot() — un analogue d'ArgumentCaptor. Un slot est déclaré avant l'appel, passé à every ou verify, et après l'exécution du test contient la valeur capturée.

kotlin
val userSlot = slot<User>()

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

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

Annotations MockK et intégration JUnit

MockK fournit les annotations @MockK et @RelaxedMockK pour créer des mocks via l'initialisation dans JUnit 5. L'extension MockKExtension crée automatiquement des mocks avant chaque test et nettoie après — similaire à MockitoExtension, mais avec la prise en charge du mode relaxé.

Exemple avec MockKExtension

L'annotation @InjectMockKs (ou l'alternative @MockK avec création explicite d'objet) injecte les mocks dans l'instance testée. Cela réduit le code répétitif et rend le code de test plus propre.

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 : que choisir pour Kotlin

Le choix entre MockK et Mockito dépend de la composition de l'équipe et du type de projet. Mockito a un écosystème plus vaste, plus d'exemples et d'intégrations, mais MockK offre une syntaxe Kotlin plus propre et une prise en charge native des fonctionnalités du langage. Pour les nouveaux projets Kotlin, MockK est recommandé comme solution plus idiomatique.

CritèreMockKMockito
SyntaxeDSL Kotlin (every, verify)Style Java (when, thenReturn)
CoroutinescoEvery, coVerify (natif)Nécessite des bibliothèques supplémentaires
Classe finalPris en charge par défautNécessite mockito-inline
KMPPris en chargeNon pris en charge
Relaxed mockIntégréPas d'équivalent
PopularitéCroissante dans la communauté KotlinDominante dans les projets Java et hybrides

Pour les projets en Kotlin pur (sans classes Java), MockK est préférable : moins de code répétitif, prise en charge native des coroutines, pas de surprises avec les classes final. Pour les projets hybrides ou les équipes ayant une expérience Java, Mockito reste une option viable — les deux bibliothèques peuvent être utilisées dans le même projet via différents modules. Lors de la migration de Mockito vers MockK, il suffit de remplacer les annotations @Mock par @MockK et de réécrire les blocs when().thenReturn() au format every { }.

Questions fréquentes

En quoi un relaxed mock diffère-t-il d'un mock normal dans MockK ?

Relaxed mock retourne des valeurs par défaut pour toutes les méthodes non configurées (liste vide, 0, null) sans lever d'exceptions. Un mock normal (strict) nécessite un stubbing explicite de chaque méthode — sinon le test échoue. Le relaxed mock est pratique pour les tests rapides, le strict pour les tests fiables.

Comment simuler des fonctions d'extension dans MockK ?

MockK prend en charge la simulation de fonctions d'extension via mockkStatic(). C'est possible car les fonctions d'extension en Kotlin sont des méthodes statiques avec le récepteur comme premier paramètre. Pour chaque fonction d'extension, vous devez spécifier la classe dans laquelle elle est déclarée.

MockK fonctionne-t-il avec Kotlin Multiplatform ?

Oui, MockK prend en charge Kotlin Multiplatform (KMP) pour le code commun. Sur les plateformes JVM, Native et JS, vous pouvez utiliser l'API commune : mockk(), every, verify. Cela fait de MockK le seul choix pour les projets KMP où Mockito ne fonctionne pas.

Comment vérifier l'ordre des appels dans MockK ?

Utilisez verifySequence { } — un bloc où les appels sont spécifiés strictement dans l'ordre attendu. Si l'ordre réel diffère, verifySequence lèvera une exception indiquant le premier appel non conforme.

Peut-on utiliser MockK et Mockito dans le même projet ?

Oui, techniquement c'est possible, mais déconseillé. Des conflits peuvent survenir au niveau de l'instrumentation de bytecode (ByteBuddy vs mockito-inline). Si un projet utilise déjà Mockito, la migration vers MockK peut être progressive via l'isolation des modules.

Résumé

  • MockK — une bibliothèque de mocking Kotlin-first avec prise en charge native du langage.
  • every { } — un DSL déclaratif pour configurer le comportement des mocks.
  • coEvery / coVerify — prise en charge des fonctions suspend dans les coroutines sans dépendances supplémentaires.
  • Relaxed mock — un mock avec valeurs par défaut qui réduit le code répétitif.
  • @MockK / @InjectMockKs — annotations pour la création automatique de mocks dans JUnit 5.
  • MockK vs Mockito — MockK est préférable pour les projets Kotlin purs et KMP.
  • verifySequence — vérification de l'ordre strict des appels de méthodes.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi