Test en Kotlin : unitaires, intégration, e2e niveau avancé

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : Pourquoi les tests avancés sont la base d'un code Kotlin fiable

Dans le développement Kotlin moderne, écrire du code n'est que la moitié du travail. La véritable maîtrise se manifeste dans la capacité à créer des systèmes fiables, testables et facilement maintenables. Les tests unitaires de base sont familiers à tous, mais lorsque le projet évolue vers une architecture de microservices ou une logique métier complexe, les simples vérifications ne suffisent plus. Les tests avancés incluent non seulement l'isolation des classes, mais aussi la vérification des interactions entre les composants (tests d'intégration) et la reproduction complète des scénarios utilisateur (E2E).

Cet article est destiné aux développeurs qui connaissent déjà les bases de Kotlin et souhaitent élever la qualité de leurs projets à un niveau supérieur. Nous aborderons trois niveaux clés de tests : unitaires, intégration et e2e, en utilisant des outils modernes : MockK, Testcontainers et Ktor Client. Vous apprendrez à écrire des tests qui non seulement "réussissent", mais protègent réellement votre code contre les régressions.



1. Tests unitaires : Isolation et mocks avec MockK

Les tests unitaires sont le fondement de la pyramide des tests. À un niveau avancé, nous ne vérifions pas simplement des fonctions, mais testons des interactions complexes entre objets en utilisant des mocks. En Kotlin, la meilleure bibliothèque pour cela est MockK.



1.1. Fonctionnalités avancées de MockK

Contrairement à Mockito, MockK est écrit spécialement pour Kotlin et prend en charge les coroutines, les lambdas et les fonctions d'extension. Voici un exemple de test d'un service qui utilise un dépôt et des coroutines :

// Service à testerclass UserService(private val repo: UserRepository) {    suspend fun getUserName(id: Long): String {        val user = repo.findById(id)        return user?.name ?: "Unknown"    }}

// Testclass UserServiceTest { private val repo = mockk<UserRepository>() private val service = UserService(repo)

@Test fun `should return user name when user exists`() = runTest { // given coEvery { repo.findById(1L) } returns User(1, "Alice")

// when val result = service.getUserName(1L)

// then assertEquals("Alice", result) coVerify(exactly = 1) { repo.findById(1L) } }

@Test fun `should return Unknown when user not found`() = runTest { // given coEvery { repo.findById(any()) } returns null

// when val result = service.getUserName(99L)

// then assertEquals("Unknown", result) }}

Points clés :

  • coEvery et coVerify — pour travailler avec des fonctions suspend.
  • mockk() crée un mock vide, spyk() — un mock partiel d'un objet réel.
  • Utilisez slots pour capturer les arguments.


1.2. Test des lambdas et des fonctions d'extension

MockK permet de mocker les fonctions d'extension, ce qui est essentiel pour des frameworks comme Ktor ou Spring WebFlux :

class StringValidator {    fun String.isValidEmail(): Boolean = this.contains("@")}

// Test@Testfun `test extension mock`() { val validator = mockk<StringValidator>() with(validator) { every { "test@mail.com".isValidEmail() } returns true every { "invalid".isValidEmail() } returns false } assertTrue("test@mail.com".isValidEmail()) assertFalse("invalid".isValidEmail())}


2. Tests d'intégration : Base de données et Testcontainers

Les tests d'intégration vérifient comment votre code interagit avec des dépendances réelles : bases de données, files d'attente de messages, API externes. C'est là que Testcontainers entre en jeu — une bibliothèque qui lance des conteneurs Docker directement pendant les tests.



2.1. Configuration de Testcontainers avec PostgreSQL

Pour une application Spring Boot, cela ressemble à ceci :

Blogs

Book Recommendations