Test Doubles — types de substituts et application

Auteur : IT Sectr Publié le : 2026-04-10 Temps de lecture : 9 min

Les Test Doubles sont des objets substituts utilisés dans les tests unitaires à la place des dépendances réelles. Le terme a été introduit par Gerard Meszaros dans le livre « xUnit Test Patterns » (2007) comme un concept général pour Mock, Stub, Fake, Spy et Dummy. Selon Martin Fowler (2024), les Test Doubles permettent d'isoler le composant testé de son environnement, rendant les tests déterministes, rapides et indépendants des services externes.

Points clés

  • Test Doubles — terme général pour tous les types d'objets substituts dans les tests
  • Mock vérifie l'interaction : quelles méthodes ont été appelées et avec quels arguments
  • Stub retourne des valeurs prédéfinies sans vérifier les appels
  • Fake — implémentation fonctionnelle simplifiée (ex. : base de données en mémoire)
  • Spy enregistre les appels pour vérification ultérieure, Dummy remplit les paramètres

Que sont les Test Doubles ?

Test Doubles est un terme issu de l'industrie automobile (cascadeur), transposé dans le développement logiciel. Comme un cascadeur remplace un acteur dans une scène dangereuse, un Test Double remplace un composant réel dans un scénario de test. Cela est nécessaire lorsque la dépendance réelle est indisponible, lente, non déterministe ou a des effets secondaires.

Le concept de Test Double englobe cinq types spécifiques, chacun résolvant sa propre tâche. La typologie de Meszaros est canonique et utilisée dans tous les guides de test modernes. La différence entre les types réside dans le degré de contrôle et de vérification : du simple remplissage de paramètres (Dummy) à la vérification complète de la séquence d'appels (Mock).

Pourquoi les Test Doubles sont nécessaires

Le but principal des Test Doubles est l'isolation du module testé. Dans le développement mobile, les dépendances réelles incluent les serveurs API, les bases de données, le système de fichiers, les capteurs de l'appareil et les services système (LocationManager, Camera, Bluetooth). L'utilisation directe de ces composants rend les tests lents, fragiles et dépendants de l'environnement. Selon Google Testing Blog (2023), les tests unitaires bien isolés s'exécutent en millisecondes, tandis que les tests d'intégration s'exécutent en secondes et minutes.

Cinq types de Test Doubles

La classification de Gerard Meszaros comprend cinq types de Test Doubles, différant par le comportement et l'objectif. Comprendre la différence entre eux est la base de tests unitaires compétents.

Dummy

Dummy est un objet passé à la méthode testée mais jamais utilisé. Dummy n'est nécessaire que pour satisfaire la signature de la méthode. En Kotlin, c'est souvent null, emptyList() ou un objet avec des stubs. Dummy ne doit contenir aucune logique — s'il est appelé, le test doit échouer.

Fake

Fake est une implémentation simplifiée mais fonctionnelle d'une interface. Contrairement à Mock et Stub, Fake contient une véritable logique métier, mais sous une forme simplifiée. Un exemple classique est InMemoryUserRepository, qui stocke les données dans une HashMap au lieu d'une base de données. Fake est utilisé lorsque vous devez tester une logique qui dépend de l'état, mais sans les frais généraux de l'infrastructure réelle.

TypeObjectifExemple
DummyRemplir un paramètrenull, objet vide
FakeImplémentation simplifiée fonctionnelleInMemoryRepository
StubRetourner une valeur fixewhen(api.getUser()).thenReturn(user)
SpyEnregistrer les appels pour vérificationverify(spy).save(user)
MockVérifier l'interactionverify(mock).sendEmail(email)

Stub

Stub retourne des valeurs prédéfinies pour des appels spécifiques. Stub ne vérifie pas s'il a été appelé — il fournit simplement des données. Dans Mockito, Stub est créé via when(method).thenReturn(value). Stub est idéal pour les tests lorsque vous avez besoin qu'une dépendance retourne une valeur spécifique, mais le fait de l'appel lui-même n'est pas important.

Spy

Spy est une enveloppe autour d'un objet réel qui enregistre tous les appels pour vérification ultérieure. Contrairement à Mock, Spy délègue les appels à l'objet réel mais permet de vérifier qu'ils ont eu lieu. Dans Mockito, Spy est créé via spy(realObject). Spy est utile pour le mocking partiel, lorsque vous voulez utiliser un objet réel mais vérifier certains appels.

Mock

Mock est un objet avec des attentes d'appel prédéfinies. Mock vérifie que des méthodes spécifiques ont été appelées avec des arguments spécifiques et dans un ordre spécifique. Contrairement à Stub, Mock se concentre sur la vérification du comportement plutôt que sur le retour de données. Mock est le type de Test Double le plus puissant et le plus utilisé dans le développement mobile.

Mock vs Stub : différences clés

La différence entre Mock et Stub cause souvent de la confusion même chez les développeurs expérimentés. La différence principale réside dans l'objectif : Stub vérifie l'état (state verification), Mock vérifie le comportement (behavior verification).

Stub répond à la question : « le code a-t-il retourné le résultat correct ? ». Mock répond à la question : « le code a-t-il appelé les bonnes méthodes avec les bons arguments ? ». Dans le développement mobile, Stub est utilisé lorsque le résultat compte (ex. : données d'un repository), tandis que Mock est utilisé lorsque les effets secondaires comptent (ex. : envoi d'e-mail, écriture dans une base de données).

kotlin
// Stub : vérification d'état
every { repository.getUsers() } returns listOf(user)
val result = useCase.getUsers()
assertEquals(1, result.size)

// Mock : vérification de comportement
every { analytics.logEvent("purchase") } returns Unit
useCase.purchase(item)
verify { analytics.logEvent("purchase") }

Exemples de Test Doubles en Kotlin

Exemples pratiques des cinq types de Test Doubles en Kotlin utilisant MockK — la bibliothèque de mocking la plus populaire pour les projets Android.

Fake : InMemoryUserRepository

kotlin
class InMemoryUserRepository : UserRepository {
    private val store = mutableMapOf<String, User>()

    override fun save(user: User) {
        store[user.email] = user
    }

    override fun findByEmail(email: String): User? {
        return store[email]
    }
}

Stub + Mock : test de UseCase

kotlin
class RegisterUseCaseTest {
    private val api = mockk<AuthApi>()
    private val repo = spyk(InMemoryUserRepository())
    private val useCase = RegisterUseCase(api, repo)

    fun `register user successfully`() = runTest {
        // Stub : retourner une réponse API fixe
        coEvery { api.register("test@test.com") } returns AuthResult.Success("token123")

        val result = useCase.execute("test@test.com")

        // Verify : vérifier que l'utilisateur a été sauvegardé
        verify { repo.save(any()) }
        assertTrue(result.isSuccess())
    }
}

Dummy : test avec paramètre inutilisé

kotlin
data class Logger(val appContext: Context, val format: FormatType)

fun `test logger with dummy context`() {
    // Dummy : Context n'est pas utilisé dans Logger
    val dummyContext = mockk<Context>()
    val logger = Logger(dummyContext, FormatType.JSON)
    assertEquals(FormatType.JSON, logger.format)
}

Quand utiliser chaque type dans le développement mobile

Le choix du type de Test Double dépend de ce qui est exactement testé : l'état, le comportement ou l'intégration. Dans le développement mobile Android et iOS, les recommandations suivantes ont été établies.

Pour ViewModel et UseCase

Lors du test de ViewModel, utilisez Mock pour les dépendances qui produisent des effets secondaires (repositories, analytics, navigation) et Stub pour les dépendances qui retournent des données (clients API, ContentProvider). Cela permet de vérifier que le ViewModel gère correctement les scénarios de succès et d'erreur.

Pour Repository et la couche de données

Au niveau Repository, préférez Fake (implémentations de base de données en mémoire) et Stub (réponses API fixes). Fake permet de tester la logique de cache et le mode hors ligne sans configurer SQLite. Stub simule différents statuts HTTP : 200, 404, 500, timeout.

  • Tests unitaires de logique métier — Mock pour toutes les dépendances externes, Dummy pour les paramètres inutilisés
  • Tests d'intégration — Fake au lieu de Mock (vérifier que les composants fonctionnent ensemble)
  • Tests UI — Stub pour les réponses API (via MockWebServer ou WireMock)
  • Tests de cache — Fake pour la base de données (en mémoire au lieu de Room/SQLite)
  • Tests d'asynchronie — Mock avec prise en charge des coroutines (MockK + Turbine pour Flow)

Erreurs courantes lors de l'utilisation de substituts

L'utilisation incorrecte des Test Doubles est l'une des causes les plus courantes de tests fragiles qui se brisent à chaque refactorisation.

Sur-moquage : utilisation excessive de Mock

L'erreur la plus courante est de moquer tout. Si chaque dépendance dans un test est remplacée par un Mock, le test cesse de vérifier le comportement réel. Mock ne doit être utilisé que pour les dépendances externes (réseau, base de données, système de fichiers, services système). Les composants internes de l'application (Value Object, data class, utilitaires simples) ne doivent pas être remplacés.

Sous-spécification : spécification insuffisante

La deuxième erreur est de créer un Mock sans définir d'attentes. Si une méthode est appelée sans every / when, Mock retourne une valeur par défaut (null, 0, false). Cela peut conduire à des tests faux-positifs, où Mock retourne silencieusement null et le test interprète cela comme un comportement correct.

Sur-vérification : vérification excessive

La troisième erreur est de vérifier chaque appel de chaque Mock. Verify ne doit être utilisé que pour les appels qui sont d'une importance critique du point de vue de la logique métier. La vérification excessive rend les tests fragiles : modifier l'ordre des appels dans le code de production brise les tests sans modifier le comportement.

Questions fréquentes

Quelle est la différence entre Mock et Stub ?

Stub retourne des données et vérifie l'état (ce qui a été retourné), tandis que Mock vérifie le comportement (quelles méthodes ont été appelées). Stub = « retourne X », Mock = « vérifie que Y a été appelé avec l'argument Z ». Dans les tests réels, un même objet agit souvent à la fois comme Stub et Mock.

Quand utiliser Fake au lieu de Mock ?

Fake est préférable à Mock lorsque l'on teste une logique qui dépend de l'état : mise en cache, mode hors ligne, transactions. Fake (implémentation en mémoire) permet de tester ces scénarios sans appels verify fragiles. Mock est mieux adapté pour vérifier l'envoi de données : analytics, push, email.

Quelle bibliothèque de Test Doubles est la meilleure pour Android ?

Pour les projets Android en Kotlin, MockK est recommandé. Il prend en charge les coroutines, les fonctions suspend, les classes scellées et les fonctions d'extension sans configuration supplémentaire. Pour les projets Java, Mockito reste la norme — la bibliothèque la plus populaire avec une documentation complète.

Comment tester Kotlin Flow avec Test Doubles ?

Pour tester Kotlin Flow, utilisez la bibliothèque Turbine avec MockK. Turbine simplifie la vérification des émissions de Flow : vous pouvez vérifier l'ordre des valeurs, la fin du flux et les exceptions. Stub pour Flow retourne flowOf(value), Mock vérifie que le Flow a été collecté.

Est-il acceptable d'utiliser Test Doubles dans les tests UI ?

Oui, mais au niveau des réponses API, pas des composants UI. Les bibliothèques MockWebServer (OkHttp) et WireMock permettent de simuler des réponses HTTP dans les tests UI. Les composants UI eux-mêmes (Compose, SwiftUI Views) ne doivent pas être remplacés — leur comportement est testé via des tests de capture d'écran et Espresso.

Résumé

  • Test Doubles — terme général pour cinq types d'objets substituts : Mock, Stub, Fake, Spy, Dummy
  • Mock vérifie le comportement (verify), Stub retourne des données (thenReturn), Fake fonctionne comme une implémentation réelle simplifiée
  • Spy enveloppe un objet réel et enregistre les appels, Dummy remplit les paramètres inutilisés
  • La typologie de Gerard Meszaros est la classification canonique utilisée dans tous les frameworks de mocking modernes
  • Pour les projets Kotlin, MockK est recommandé, pour Java — Mockito, pour iOS — Cuckoo ou OHHTTPStubs
  • Erreurs courantes : sur-moquage (tout remplacer), sous-spécification (attentes non définies), sur-vérification (verify excessif)
  • Fake est préférable à Mock lors du test de logique avec état — mise en cache, mode hors ligne et transactions

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