JUnit est un framework standard pour les tests unitaires dans l'écosystème Java et Kotlin, utilisé dans le développement Android pour vérifier la logique métier au niveau de composants isolés. Le framework fournit un ensemble d'annotations, de méthodes d'assertion et un Test Runner pour la découverte et l'exécution automatiques des tests. Selon JUnit.org, la bibliothèque reste la solution la plus populaire pour les tests unitaires dans l'écosystème JVM : plus de 70 % des projets Java utilisent JUnit dans une version quelconque.
Points clés
JUnit est un framework open-source pour écrire et exécuter des tests unitaires reproductibles en Java et Kotlin. Il fait partie de l'écosystème xUnit, une famille de frameworks basés sur l'architecture de Kent Beck et Erich Gamma, et est l'outil de test standard dans Android Studio et IntelliJ IDEA.
La tâche principale de JUnit est d'isoler un petit fragment de code (méthode, classe) et de vérifier son comportement dans des conditions contrôlées. Les tests sont écrits comme des classes Java/Kotlin ordinaires avec des annotations, et le framework se charge de la découverte des tests, de la gestion du cycle de vie et de la collecte des statistiques d'exécution.
La première version de JUnit est apparue en 1997 et a radicalement changé l'approche de développement en popularisant les pratiques de Test-Driven Development (TDD). Aujourd'hui, JUnit 5 (Jupiter) est la version actuelle, complètement repensée avec une architecture modulaire prenant en charge Java 8+ et les extensions.
Le mécanisme d'exécution de JUnit est basé sur le modèle Test Runner, qui scanne le classpath, trouve les méthodes avec l'annotation @Test, crée une instance de la classe de test et exécute les méthodes dans un ordre spécifique. Le Test Runner gère le cycle de vie : BeforeAll → BeforeEach → Test → AfterEach → AfterAll.
JUnit encapsule chaque méthode de test dans une instance de classe séparée, garantissant ainsi l'isolation entre les tests. Cela signifie que les champs de la classe ne conservent pas l'état entre différentes méthodes @Test — chaque test commence avec un objet propre.
Le test le plus simple dans JUnit est une méthode avec l'annotation @Test qui appelle le code testé et vérifie le résultat à l'aide d'une assertion. Si l'assertion échoue, le test est considéré comme échoué et JUnit signale l'erreur.
@Test
void additionShouldReturnCorrectSum() {
var calculator = new Calculator();
var result = calculator.add(2, 3);
assertEquals(5, result);
}
Le Test Runner trouve automatiquement une telle méthode, l'exécute et signale le résultat. Si la méthode ne lève pas d'exception — le test réussit (green). Si une assertion échoue — le test échoue (red).
Les annotations dans JUnit définissent quand et comment le code de test doit s'exécuter. Dans JUnit 5, les annotations se trouvent dans le package org.junit.jupiter.api et couvrent toutes les étapes : préparation des données, exécution du test, nettoyage des ressources.
| Annotation | Objectif | Exécution |
|---|---|---|
| @Test | Marque une méthode de test | Une fois par appel |
| @BeforeEach | Préparation avant chaque test | Avant chaque @Test |
| @BeforeAll | Initialisation unique de la classe | Une fois avant tous les tests |
| @AfterEach | Nettoyage après chaque test | Après chaque @Test |
| @AfterAll | Finalisation unique de la classe | Une fois après tous les tests |
| @DisplayName | Nom lisible du test | Décoration |
Considérons une classe de test complète avec un cycle de vie approprié. La méthode setUp crée une nouvelle instance de Calculator avant chaque test, et tearDown libère les ressources — par exemple, la fermeture des descripteurs de fichiers ou des connexions à la base de données.
class CalculatorTest {
private Calculator calculator;
@BeforeEach
void setUp() {
calculator = new Calculator();
}
@Test
void subtractionShouldReturnCorrectResult() {
int result = calculator.subtract(10, 4);
assertEquals(6, result);
}
@AfterEach
void tearDown() {
calculator.reset();
}
}
Les assertions sont des méthodes statiques qui comparent le résultat réel avec le résultat attendu et lèvent une exception en cas de non-correspondance. JUnit 5 propose la classe org.junit.jupiter.api.Assertions avec plus de 25 méthodes pour différents scénarios de vérification — de la simple comparaison de valeurs aux vérifications de délai d'attente et aux assertions groupées.
Une attention particulière mérite la méthode assertThrows, qui permet de vérifier que le code gère correctement les situations d'erreur — division par zéro, passage de null, dépassement de limites.
@Test
void divisionByZeroShouldThrowException() {
Calculator calc = new Calculator();
ArithmeticException exception = assertThrows(
ArithmeticException.class,
() -> calc.divide(10, 0)
);
assertEquals("Cannot divide by zero", exception.getMessage());
}
Les tests paramétrés permettent d'exécuter la même méthode de test avec différents ensembles d'arguments. Dans JUnit 5, cela se fait à l'aide de l'annotation @ParameterizedTest combinée avec une source de données — @ValueSource, @CsvSource, @MethodSource ou @EnumSource.
Cette approche réduit radicalement la duplication de code : au lieu de dix tests identiques pour différentes valeurs, on écrit une seule méthode paramétrée. Selon le Google Testing Blog, la paramétrisation réduit le volume de code de test de 40 à 60 % sans perte de couverture.
L'annotation @CsvSource transmet plusieurs lignes séparées par des virgules au test. Chaque ligne correspond à une exécution de test. JUnit convertit automatiquement les valeurs chaîne en types requis : int, long, String et autres.
@ParameterizedTest
@CsvSource({
"1, 1, 2",
"2, 3, 5",
"10, 20, 30",
"-1, 1, 0"
})
void additionWithMultipleInputs(int a, int b, int expected) {
assertEquals(expected, a + b);
}
Lorsque les données d'entrée sont plus complexes que de simples nombres ou chaînes, on utilise @MethodSource. Il fait référence à une méthode statique qui retourne un Stream d'arguments — par exemple, un Stream d'Arguments ou un Stream d'objets User pour tester la couche DAO.
Dans le développement Android, JUnit est utilisé avec AndroidX Test, qui fournit des extensions pour tester Activity, Content Provider et d'autres composants Android. JUnit gère les tests unitaires exécutés sur la JVM sans émulateur, tandis qu'AndroidX Test gère les tests instrumentés sur l'appareil.
Pour ajouter JUnit 5 à un projet Android, il suffit d'inclure la dépendance org.junit.jupiter:junit-jupiter dans le build.gradle au niveau du module. Le plugin AGP Gradle prend en charge l'exécution des tests JUnit 5 sur la JVM via le Test Runner standard.
// build.gradle.kts
android {
testOptions {
unitTests.isIncludeAndroidResources = true
}
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.11.0")
testImplementation("androidx.test:core-ktx:1.6.1")
}
En pratique, JUnit est le plus souvent utilisé pour tester ViewModel et les repositories — des couches qui ne nécessitent pas de contexte Android ni d'émulateur. Un tel test s'exécute en millisecondes et peut être exécuté des centaines de fois sans perdre de temps.
JUnit 5 (Jupiter) n'est pas simplement une nouvelle version, mais une plateforme complètement repensée divisée en trois modules : JUnit Platform (exécution des tests sur la JVM), JUnit Jupiter (API pour écrire des tests) et JUnit Vintage (rétrocompatibilité avec JUnit 4). Cette modularité permet de connecter différents Test Engines — par exemple, Spek pour Kotlin ou TestNG.
| Caractéristique | JUnit 4 | JUnit 5 |
|---|---|---|
| Package | org.junit | org.junit.jupiter |
| Annotation de base | @Test (de junit.framework) | @Test (de org.junit.jupiter.api) |
| Before/After | @Before, @After, @BeforeClass | @BeforeEach, @AfterEach, @BeforeAll |
| Paramétrés | @RunWith(Parameterized.class) | @ParameterizedTest + @ValueSource |
| Extension | @Rule, @ClassRule | @ExtendWith, API plus flexible |
| Java min | Java 5 | Java 8+ |
Migrer de JUnit 4 à JUnit 5 ne nécessite pas de réécrire tous les tests — il suffit d'ajouter JUnit Vintage Engine et les anciens tests continueront de fonctionner. Il est recommandé d'écrire les nouveaux tests avec JUnit 5 pour profiter des extensions, des assertions lambda et du support intégré de la paramétrisation.
Foire aux questions
JUnit est un framework pour écrire et exécuter des tests, tandis que Mockito est une bibliothèque pour créer des objets mock. Ils sont utilisés ensemble : JUnit gère l'exécution du test et Mockito remplace les dépendances de la classe testée.
Oui, JUnit 5 est entièrement compatible avec les projets Android. Pour les tests unitaires, il suffit d'ajouter la dépendance junit-jupiter dans build.gradle. Les tests instrumentés continuent de fonctionner via AndroidX Test Runner.
Au minimum, une seule annotation @Test avant la méthode suffit. Pour l'initialisation et le nettoyage, @BeforeEach et @AfterEach sont recommandées mais pas obligatoires.
Le Test Runner est un composant de JUnit qui scanne le classpath, trouve les méthodes avec l'annotation @Test, crée des instances de classes de test et exécute les tests. Dans JUnit 5, ce rôle est assuré par JUnit Platform avec les Test Engines connectés.
Utilisez assertThrows(Class, Executable) — il prend le type d'exception attendu et une lambda avec l'appel de méthode. JUnit vérifie que l'exception a bien été levée et la retourne pour inspection supplémentaire.
Résumé
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.
Lisez aussi