Tutorial do JUnit5

Tutorial JUnit5

Neste tutorial do JUnit, iremos apresentar os conceitos básicos do JUnit5 e suas novas funcionalidades usando exemplos. No mundo Java, o JUnit é um dos frameworks populares usados para implementar testes unitários em código Java. O JUnit ajuda principalmente os desenvolvedores a testar seu código na JVM por si mesmos.

Arquitetura do JUnit5

Plataforma JUnit

  • Inicia frameworks de teste na JVM
  • Tem a API TestEngine usada para construir um framework de teste que roda na plataforma JUnit

Jupiter JUnit

  • Mistura de novo modelo de programação para escrever testes e modelo de extensão para extensões
  • Adição de novas anotações como @BeforeEach, @AfterEach, @AfterAll, @BeforeAll etc.

JUnit Vintage

  • Fornece suporte para executar testes das versões anteriores do JUnit 3 e 4 nesta nova plataforma

Dependências do Maven para JUnit

Para implementar casos de teste baseados no JUnit5 em um projeto, adicione a seguinte dependência ao arquivo pom.xml do projeto:

  • Biblioteca 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>
  • Provedor surefire do Maven para executar os testes unitários onde a IDE não tem suporte para o JUnit5 (se a IDE tiver suporte, este ponto não é necessário)
<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>

Novas Funcionalidades do JUnit5

É necessário o Java 8 ou superior em tempo de execução. Mas ainda é possível testar código compilado usando versões anteriores do Java. Foram introduzidas várias novas funcionalidades.

Annotations do JUnit

Abaixo estão algumas anotações comumente usadas fornecidas nele:

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 ---**");
  }


}

Pode-se executar a classe de teste JUnit acima em Eclipse -> Executar Como -> Teste JUnit.

Assertivas do JUnit

Cada método de teste deve ser avaliado em relação a uma condição verdadeira usando assertivas para que o teste possa continuar a ser executado. As assertivas do JUnit Jupiter são mantidas na classe org.junit.jupiter.api.Assertions. Todos os métodos são estáticos.

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")
	 );
	 //descomente o código abaixo e entenda a execução de cada assertiva
     /*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());
}

Importações do JUnit5

As classes de teste precisam de uma declaração de importação org.junit.jupiter.api.Test e não org.junit.Test. Além disso, os métodos de teste não precisam ser públicos e podem estar no pacote local.

import org.junit.jupiter.api.Test;

JUnit5 Assumptions

As Asserções são métodos estáticos na classe org.junit.jupiter.api.Assumptions. Eles executarão um teste somente quando a condição especificada for atendida, caso contrário, o teste será abortado. O teste abortado não causará falha na construção. Quando uma assunção falha, org.opentest4j.TestAbortedException é lançada e o teste é pulado.

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 Teste Aninhadas JUnit

Testes aninhados permitem criar classes aninhadas e executar todos os seus métodos de teste. As classes internas devem ser não estáticas. Basta anotar as classes internas com @Nested e todos os métodos de teste dentro dela serão executados.

@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 ---**");
               }
        }
    }

Exceção de Teste JUnit

Há situações em que métodos devem lançar uma exceção sob uma condição específica. assertThrows irá falhar no teste se o método dado não lançar a exceção especificada.

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

Execução de Teste JUnit

Os testes unitários podem ser executados de várias maneiras, duas delas são as seguintes:

  • Utilize o Eclipse IDE Oxygen.3a (4.7.3a) Release e abra o arquivo de teste a ser executado. Clique com o botão direito no arquivo e escolha a opção Executar Como, seguido de Teste JUnit
  • Utilize o comando mvn test no prompt de comando do Windows

Resumo

Exploramos o JUnit5 e suas novas funcionalidades com alguns exemplos. Também vimos como podemos usar anotações JUnit, asserções, suposições, exceções e escrever classes de teste aninhadas.

Você pode baixar o projeto de exemplo completo do nosso Repositório GitHub.

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