Maven ne trouve pas de tests JUnit à exécuter

Maven affiche "No tests were executed" ou "No tests found for surefire" alors que vos classes de test sont pourtant là. C'est l'un des pièges classiques de Maven — surtout depuis la transition de JUnit 4 à JUnit 5.

Symptôme

$ mvn test
...
[INFO] --- maven-surefire-plugin:3.2.5:test (default-test) ---
[INFO] No tests to run.
[INFO] BUILD SUCCESS

Le build passe, mais aucun test n'a tourné — ce qui est pire qu'un échec puisque la suppression silencieuse donne une fausse confiance.

Cause 1 — nommage des classes de test

Par défaut, maven-surefire-plugin exécute les classes qui correspondent à ces patterns :

  • **/Test*.java — commence par Test
  • **/*Test.java — finit par Test
  • **/*Tests.java — finit par Tests
  • **/*TestCase.java

Une classe nommée UserValidation ne sera jamais exécutée. Renommez-la UserValidationTest.

Cause 2 — Surefile trop ancien pour JUnit 5

JUnit 5 (jupiter) nécessite maven-surefire-plugin version 2.22.0 ou ultérieure. Les versions antérieures ne connaissent pas le provider JUnit Platform et ignorent silencieusement les tests annotés @Test importés depuis org.junit.jupiter.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>3.2.5</version>
</plugin>

Cause 3 — dépendance JUnit manquante ou mal scopée

Pour JUnit 5 :

<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter</artifactId>
  <version>5.11.4</version>
  <scope>test</scope>
</dependency>

Pour JUnit 4 (legacy) :

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.13.2</version>
  <scope>test</scope>
</dependency>

Sans le scope test, les tests compilent mais ne sont pas récupérés par Surefire.

Cause 4 — confusion entre @Test de JUnit 4 et JUnit 5

Les deux annotations portent le même nom mais vivent dans des packages différents :

VersionImport
JUnit 4import org.junit.Test;
JUnit 5import org.junit.jupiter.api.Test;

Si votre projet n'a que la dépendance JUnit 5 mais que vos tests importent org.junit.Test (JUnit 4), Surefire ne les trouve pas. L'IDE peut même ne pas signaler d'erreur si l'ancienne classe est toujours dans le classpath transitif.

Cause 5 — répertoire de tests incorrect

Maven cherche les tests dans src/test/java. Si vos fichiers sont ailleurs (tests/, src/tests/), ou dans src/main/java, ils seront ignorés. Respectez la convention ou reconfigurez :

<build>
  <testSourceDirectory>tests/java</testSourceDirectory>
</build>

Cause 6 — classes abstraites ou internes

Surefire ignore :

  • Les classes abstract — elles ne peuvent pas être instanciées.
  • Les classes package-private dans certaines configurations.
  • Les classes imbriquées non static sauf annotation @Nested (JUnit 5).

Cause 7 — option skipTests ou -DskipTests

Un flag passé par inadvertance :

mvn test -DskipTests   # ne compile ni n'exécute
mvn test -Dmaven.test.skip=true

Ou dans le POM :

<properties>
  <skipTests>true</skipTests>
</properties>

Vérifiez toute configuration parente héritée.

Diagnostic

Lancez avec la sortie debug :

mvn test -X 2>&1 | grep -i "include\|exclude\|surefire"

Surefire liste les patterns d'inclusion/exclusion et les classes qu'il scanne. Vous verrez si vos fichiers correspondent.

Configuration complète qui marche

<project>
  <properties>
    <maven.compiler.release>21</maven.compiler.release>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter</artifactId>
      <version>5.11.4</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.2.5</version>
      </plugin>
    </plugins>
  </build>
</project>
// src/test/java/com/example/UserValidationTest.java
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class UserValidationTest {
    @Test
    void emailValide() {
        assertTrue(User.isValidEmail("alice@example.com"));
    }
}

Avec cette configuration, mvn test trouve et exécute UserValidationTest sans aucune option supplémentaire.