Tutoriel JUnit5

Tutoriel JUnit5

Dans ce tutoriel Junit, nous présenterons les bases de JUnit5 et ses nouvelles fonctionnalités à l’aide d’exemples. Dans le monde Java, JUnit est l’un des frameworks populaires utilisés pour implémenter des tests unitaires sur du code Java. JUnit aide principalement les développeurs à tester leur code sur la JVM eux-mêmes.

Architecture de JUnit5

Plateforme JUnit

  • Lance les frameworks de test sur la JVM
  • Dispose d’une API TestEngine utilisée pour construire un framework de test qui s’exécute sur la plateforme JUnit

Jupiter JUnit

  • Mélange du nouveau modèle de programmation pour écrire des tests et du modèle d’extension pour les extensions
  • Ajout de nouvelles annotations telles que @BeforeEach, @AfterEach, @AfterAll, @BeforeAll, etc.

JUnit Vintage

  • Fournit un support pour exécuter les tests des versions précédentes de JUnit 3 et 4 sur cette nouvelle plateforme

Dépendances Maven pour JUnit

Pour implémenter des cas de test basés sur JUnit5 dans un projet, ajoutez la dépendance suivante au fichier pom.xml du projet:

  • Bibliothèque JUnit 5
<dependency>
     <groupId>org.junit.jupiter</groupId>
     <artifactId>junit-jupiter-engine</artifactId>
     <version>5.1.1</version>
     <scope>test</scope>
</dependency>
<dependency>
     <groupId>org.junit.platform</groupId>
     <artifactId>junit-platform-runner</artifactId>
     <version> 1.1.1</version>
     <scope>test</scope>
</dependency>
  • Fournisseur Maven Surefire de JUnit5 pour exécuter les tests unitaires lorsque l’IDE ne prend pas en charge JUnit5 (si l’IDE prend en charge, ce point n’est pas nécessaire)
<plugin>
     <artifactId>maven-surefire-plugin</artifactId>
     <version>2.19.1</version>
     <dependencies>
          <dependency>
               <groupId>org.junit.platform</groupId>
               <artifactId>junit-platform-surefire-provider</artifactId>
               <version>1.0.2</version>
          </dependency>
     </dependencies>
</plugin>

Nouvelles fonctionnalités de JUnit5

Il nécessite Java 8 ou une version ultérieure à l’exécution. Mais on peut toujours tester du code compilé à l’aide de versions Java précédentes. De nouvelles fonctionnalités ont été introduites.

Annotations JUnit

Voici quelques annotations couramment utilisées fournies :

Annotation Description
@Test Denotes a test method
@DisplayName Declares a custom display name for the test class or test method
@BeforeEach Denotes that the annotated method should be executed before each test method
@AfterEach Denotes that the annotated method should be executed after each test method
@BeforeAll Denotes that the annotated method should be executed before all test methods
@AfterAll Denotes that the annotated method should be executed after all test methods
@Disable Used to disable a test class or test method
@Nested Denotes that the annotated class is a nested, non-static test class
@Tag Declare tags for filtering tests
@ExtendWith Register custom extensions
package com.journaldev;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class JUnit5Sample1Test {

  @BeforeAll
  static void beforeAll() {
    System.out.println("**--- Executed once before all test methods in this class ---**");
  }

  @BeforeEach
  void beforeEach() {
    System.out.println("**--- Executed before each test method in this class ---**");
  }

  @Test
  void testMethod1() {
    System.out.println("**--- Test method1 executed ---**");
  }

  @DisplayName("Test method2 with condition")
  @Test
  void testMethod2() {
    System.out.println("**--- Test method2 executed ---**");
  }

  @Test
  @Disabled("implementation pending")
  void testMethod3() {
	  System.out.println("**--- Test method3 executed ---**");
  }

  @AfterEach
  void afterEach() {
    System.out.println("**--- Executed after each test method in this class ---**");
  }

  @AfterAll
  static void afterAll() {
    System.out.println("**--- Executed once after all test methods in this class ---**");
  }


}

Nous pouvons exécuter la classe de test JUnit ci-dessus dans Eclipse -> Exécuter en tant que -> Test JUnit.

Assertions JUnit

Chaque méthode de test doit être évaluée par rapport à une condition vraie en utilisant des assertions afin que le test puisse continuer à s’exécuter. Les assertions JUnit Jupiter sont conservées dans la classe org.junit.jupiter.api.Assertions. Toutes les méthodes sont statiques.

Assertion Description
assertEquals(expected, actual) Fails when expected does not equal actual
assertFalse(expression) Fails when expression is not false
assertNull(actual) Fails when actual is not null
assertNotNull(actual) Fails when actual is null
assertAll() Group many assertions and every assertion is executed even if one or more of them fails
assertTrue(expression) Fails if expression is not true
assertThrows() Class to be tested is expected to throw an exception
@Test
void testAssertEqual() {
	 assertEquals("ABC", "ABC");
	 assertEquals(20, 20, "optional assertion message");
	 assertEquals(2 + 2, 4);
}

@Test
void testAssertFalse() {
	 assertFalse("FirstName".length() == 10);
	 assertFalse(10 > 20, "assertion message");
}

@Test
void testAssertNull() {
     String str1 = null;
	 String str2 = "abc";
	 assertNull(str1);
	 assertNotNull(str2);	
}

@Test
void testAssertAll() {
	 String str1 = "abc";
	 String str2 = "pqr";
	 String str3 = "xyz";
	 assertAll("numbers",
	      () -> assertEquals(str1,"abc"),
		  () -> assertEquals(str2,"pqr"),
		  () -> assertEquals(str3,"xyz")
	 );
	 // décommentez le code ci-dessous et comprenez l'exécution de chaque assert
     /*assertAll("numbers",
		  () -> assertEquals(str1,"abc"),
		  () -> assertEquals(str2,"pqr1"),
		  () -> assertEquals(str3,"xyz1")
	 );*/
}

@Test
void testAssertTrue() {
	 assertTrue("FirstName".startsWith("F"));
	 assertTrue(10  {
	      throw new IllegalArgumentException("Illegal Argument Exception occured");
	 });
	 assertEquals("Illegal Argument Exception occured", exception.getMessage());
}

Imports JUnit5

Ses classes de test nécessitent une déclaration d’importation org.junit.jupiter.api.Test et non org.junit.Test. De plus, les méthodes de test ne doivent pas être publiques et sont accessibles depuis le package local.

import org.junit.jupiter.api.Test;

JUnit5 Assumptions

Les hypothèses sont des méthodes statiques dans la classe org.junit.jupiter.api.Assumptions. Elles exécuteront un test uniquement lorsque la condition spécifiée est remplie, sinon le test sera abandonné. Le test abandonné ne provoquera pas d’échec de construction. Lorsqu’une hypothèse échoue, org.opentest4j.TestAbortedException est déclenchée et le test est ignoré.

Assumptions Description
assumeTrue Execute the body of lamda when the positive condition hold else test will be skipped
assumeFalse Execute the body of lamda when the negative condition hold else test will be skipped
assumingThat Portion of the test method will execute if an assumption holds true and everything after the lambda will execute irrespective of the assumption in assumingThat() holds
@Test
void testAssumeTrue() {
     boolean b = 'A' == 'A';
     assumeTrue(b);
     assertEquals("Hello", "Hello");
}

@Test
@DisplayName("test executes only on Saturday")
public void testAssumeTrueSaturday() {
     LocalDateTime dt = LocalDateTime.now();
     assumeTrue(dt.getDayOfWeek().getValue() == 6);
     System.out.println("further code will execute only if above assumption holds true");
}

@Test
void testAssumeFalse() {
     boolean b = 'A' != 'A';
     assumeFalse(b);
     assertEquals("Hello", "Hello");
}

@Test
void testAssumeFalseEnvProp() {
     System.setProperty("env", "prod");
     assumeFalse("dev".equals(System.getProperty("env")));
     System.out.println("further code will execute only if above assumption hold");
}

@Test
void testAssumingThat() {
     System.setProperty("env", "test");
     assumingThat("test".equals(System.getProperty("env")),
          () -> {
               assertEquals(10, 10);
               System.out.println("perform below assertions only on the test env");
               });

     assertEquals(20, 20);
     System.out.println("perform below assertions on all env");
}

Classes de test imbriquées JUnit

Les tests imbriqués permettent de créer des classes imbriquées et d’exécuter toutes leurs méthodes de test. Les classes internes doivent être non statiques. Il suffit d’annoter les classes internes avec @Nested et toutes les méthodes de test à l’intérieur seront exécutées.

@BeforeAll
static void beforeAll() {
     System.out.println("**--- JUnit5Sample4Test :: beforeAll :: Executed once before all test methods ---**");
}
 
@BeforeEach
void beforeEach() {
	 System.out.println("**--- JUnit5Sample4Test :: beforeEach :: Executed before each test method ---**");
}

@AfterEach
void afterEach() {
	 System.out.println("**--- JUnit5Sample4Test :: afterEach :: Executed after each test method ---**");
}

@AfterAll
static void afterAll() {
	 System.out.println("**--- JUnit5Sample4Test :: afterAll :: Executed after all test method ---**");
}
 
     @Nested
     class InnerClass {
 
          @BeforeEach
          void beforeEach() {
               System.out.println("**--- InnerClass :: beforeEach :: Executed before each test method ---**");
          }
 
          @AfterEach
          void afterEach() {
        	   System.out.println("**--- InnerClass :: afterEach :: Executed after each test method ---**");
          }
 
          @Test
          void testMethod1() {
        	   System.out.println("**--- InnerClass :: testMethod1 :: Executed test method1 ---**");
          }
 
          @Nested
          class InnerMostClass {
 
               @BeforeEach
               void beforeEach() {
                    System.out.println("**--- InnerMostClass :: beforeEach :: Executed before each test method ---**");
               }
 
               @AfterEach
               void afterEach() {
            	    System.out.println("**--- InnerMostClass :: afterEach :: Executed after each test method ---**");
               }
 
               @Test
               void testMethod2() {
            	    System.out.println("**--- InnerMostClass :: testMethod2 :: Executed test method2 ---**");
               }
        }
    }

Exception de test JUnit

Il existe des situations dans lesquelles des méthodes sont censées lever une exception dans une condition spécifique. assertThrows échouera le test si la méthode donnée ne lève pas l’exception spécifiée.

Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
     throw new IllegalArgumentException("Illegal Argument Exception occured");
});
assertEquals("Illegal Argument Exception occured", exception.getMessage());

Exécution des tests JUnit

Les tests unitaires peuvent être exécutés de plusieurs manières, deux des façons sont les suivantes :

  • Utilisez l’IDE Eclipse Oxygen.3a (4.7.3a) Release et ouvrez le fichier de test à exécuter. Faites un clic droit sur le fichier et choisissez l’option Exécuter en suivie de JUnit Test
  • Utilisez la commande `mvn test` dans l’invite de commandes Windows

Résumé

Nous avons exploré JUnit5 et ses nouvelles fonctionnalités avec quelques exemples. Nous avons également examiné comment nous pouvons utiliser les annotations, assertions, hypothèses, exceptions et écrire des classes de tests imbriquées avec JUnit

Vous pouvez télécharger le projet exemple complet depuis notre Dépôt GitHub.

Source:
https://www.digitalocean.com/community/tutorials/junit5-tutorial