JUnit Teste parametrizado com exemplo usando @Parameters

⚡ Resumo Inteligente

Testes parametrizados em JUnit Execute o mesmo método de teste repetidamente com diferentes valores de entrada, de forma que um único método cubra vários cenários. As anotações `@RunWith` e `@Parameters` fornecem o conjunto de dados para cada iteração.

  • 🔘 Fonte de dados: Um método estático @Parameters retorna uma coleção de arrays, e cada array se torna uma iteração de teste.
  • ☑️ Corredor: @RunWith(Parameterized.class) substitui o bloco padrãoJUnitO 4ClassRunner reconstrói a classe uma vez por linha de dados.
  • ✅ Construtor: Um construtor público armazena uma única linha de dados nos campos da instância que o método de teste verifica.
  • 🧪 Exemplo resolvido: Cinco linhas de entrada executam o teste sum(), e o JUnit Visualizar relatórios. Executa 5/5 vezes sem falhas.
  • 🛠️ JUnit 5: A anotação @ParameterizedTest com @ValueSource, @CsvSource ou @MethodSource remove tanto o executor quanto o construtor.
  • 📌 Armadilhas: Um método @Parameters não estático, dois construtores públicos ou a ausência da dependência junit-jupiter-params interrompem a execução.

JUnit teste parametrizado usando anotações @RunWith e @Parameters

O que é um teste parametrizado em JUnit?

A teste parametrizado É um teste que executa o mesmo método de teste repetidamente, usando valores diferentes. Ele ajuda os desenvolvedores a economizar tempo ao escrever testes que diferem apenas em suas entradas e resultados esperados.

Usando um teste parametrizado, é possível configurar um método de teste que recupera dados de alguma fonte de dados. Isso o torna a forma mais simples de... teste baseado em dados disponível dentro JUnit por si só, sem necessidade de biblioteca externa.

Considere um teste simples que soma números diferentes. O código pode ser semelhante a este:

JUnit O método de teste repete três chamadas assertEquals para o método sum.

A abordagem acima leva a muita redundância. Cada novo par de números precisa de uma nova instrução assert dentro do mesmo método, e uma falha na primeira asserção oculta todas as asserções subsequentes.

É necessária uma abordagem mais simples. Usando um teste parametrizado, você pode adicionar um único método que fornece dez entradas de dados, e seu teste será executado dez vezes automaticamente.

Etapas para criar um parametrizado JUnit Testar

O código a seguir mostra um exemplo de um teste parametrizado. Ele testa o método sum() da classe Airthematic, que é a grafia usada em todo o projeto de exemplo.

Passo 1) Crie uma classe. Neste exemplo, vamos inserir dois números usando o método sum(int, int), que retornará a soma dos números fornecidos.

Classe Airthematic declarando um método público sum que soma dois argumentos do tipo int.

Passo 2) Crie uma classe de teste parametrizada.

Cabeçalho da classe de teste anotado com @RunWith(Parameterized.class) e quatro campos privados

Code Explicação

  • Code Linha 11: Anote sua classe de teste usando @RunWith(Parameterized.class).
  • Code Linha 13: Declarar a variável 'firstNumber' como privada e digitar como int.
  • Code Linha 14: Declarando a variável 'secondNumber' como privada e do tipo int.
  • Code Linha 15: Declarando a variável 'expectedResult' como privada e do tipo int.
  • Code Linha 16: Declarando a variável 'airthematic' como privada e do tipo Airthematic.

@Correr com(nome_da_classe.classe): o @Correr com A anotação é usada para especificar o nome da classe do executor. Se não especificarmos nenhum tipo como parâmetro, o ambiente de execução escolherá. BloquearJUnit4ClassRunner por padrão.

Esta classe é responsável por executar os testes com uma nova instância de teste. Ela é responsável por invocar... JUnit métodos de ciclo de vida, como configuração (associar recursos) e desmontagem (liberar recursos), que são descritos no JUnit dispositivo de teste tutorial.

Para parametrizar, você precisa anotar a classe usando @RunWith e passar o arquivo .class necessário para ser testado.

Passo 3) Crie um construtor que armazene os dados de teste. Ele armazena 3 variáveis.

Construtor de teste parametrizado que atribui três argumentos inteiros a campos de instância.

Passo 4) Crie um método estático que gere e retorne dados de teste.

Método de entrada estático anotado com @Parameterized.Parameters que retorna um array de objetos bidimensional.

Code Linha 32,33: Criando uma matriz bidimensional (fornecendo parâmetros de entrada para adição). Usando o método `asList`, convertemos os dados em um tipo `List`, já que o tipo de retorno do método de entrada é uma `Collection`.

Code Linha 30: Com o @Parâmetros anotação para criar um conjunto de dados de entrada para executar nosso teste.

O método estático identificado pela anotação @Parameters retorna uma Collection onde cada entrada na Collection será o dado de entrada para uma iteração do teste. Considere o elemento {1,2,3}. Aqui:

  • primeiroNúmero = 1
  • segundoNúmero = 2
  • resultadoEsperado = 3

Aqui, cada elemento do array será passado para o construtor, um de cada vez, à medida que a classe for instanciada várias vezes. Os cinco arrays declarados no exemplo, portanto, produzem as seguintes cinco execuções:

Iteração primeiroNúmero segundoNúmero resultado esperado Linha de console
1 2 3 Soma de Numbers = : 3
11 22 33 Soma de Numbers = : 33
111 222 333 Soma de Numbers = : 333
10 9 19 Soma de Numbers = : 19
100 9 109 Soma de Numbers = : 109

Passo 5) O código completo.

Listagem completa do AirthematicTest com importações, construtor, método @Parameters e método @Test.

Code Explicação:

  • Code Linha 25: Utilizando a anotação `@Before` para configurar os recursos (Airthematic.class neste caso). A anotação `@Before` é usada aqui para ser executada antes de cada caso de teste. Ela contém a pré-condição do teste.
  • Code Linha 36: Utilizando a anotação @Test para criar nosso teste.
  • Code Linha 39: Criando um declaração assert para verificar se nossa soma é equivalente ao que esperávamos.

Passo 6) Crie uma classe de execução de testes para executar o teste parametrizado:

Classe TestRunner passando AirthematicTest.class para JUnitCore.runClasses e falhas de impressão

Code Explicação:

  • Code Linha 8: Declarando o método principal da classe Test que executará nosso JUnit teste.
  • Code Linha 9: Executando casos de teste usando JUnitCore.runClasses, que recebe o nome da classe de teste como parâmetro (em nosso exemplo, estamos usando AirthematicTest.class).
  • Code Linha 11: Processando o resultado usando um laço `for` e imprimindo o resultado com falha.
  • Code Linha 13: Imprimindo o resultado bem-sucedido.

Saída:

Aqui está o resultado, que mostra um teste bem-sucedido, sem falhas. trace, conforme indicado abaixo. Observe que o JUnit A visualização lista uma entrada por linha de dados em vez de um único teste:

Eclipse JUnit Visualizar relatório. Executa 5/5 vezes sem erros e sem falhas para a classe parametrizada.

Veja o resultado no console, que mostra a soma dos dois números:

Eclipse console imprimindo uma soma de Numbers linha para cada uma das cinco linhas de parâmetros

Testes parametrizados em JUnit 5 com @ParameterizedTest

O exemplo acima foi escrito para JUnit 4. JUnit A versão 5 (Jupiter) abandona completamente o modelo de executor, portanto, o `@RunWith(Parameterized.class)`, o construtor de dados e os campos de instância desaparecem. JUnit O código 4 mostrado acima não está obsoleto: ele ainda funciona sem alterações no JUnit Plataforma através do mecanismo clássico. Novos testes, no entanto, são normalmente escritos com @ParameterizedTest.

São necessárias duas dependências: junit-jupiter-api para as anotações de teste e junit-jupiter-params para o suporte parametrizado. Sem o segundo artefato, as anotações de origem não serão resolvidas.

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

class AirthematicTest {

    // one row per iteration, no constructor and no runner
    @ParameterizedTest(name = "{0} + {1} = {2}")
    @CsvSource({"1, 2, 3", "11, 22, 33", "111, 222, 333", "10, 9, 19", "100, 9, 109"})
    void sumOfTwoNumbers(int firstNumber, int secondNumber, int expectedResult) {
        assertEquals(expectedResult, new Airthematic().sum(firstNumber, secondNumber));
    }
}

Júpiter oferece diversas fontes de argumentos, e a mais adequada depende do formato dos dados:

Anotação de origem Abastecimento Use-o quando
@ValueSource Uma única coluna de literais O teste aceita exatamente um argumento.
@CsvSource Linhas separadas por vírgulas em linha Pequenas tabelas de números e strings são lidas sem problemas no arquivo.
@CsvFileSource Linhas lidas de um arquivo CSV no classpath de teste O conjunto de dados é grande ou mantido fora do código.
@MethodSource Uma fábrica estática que retorna um fluxo de argumentos. São necessários objetos reais, valores calculados ou dados aleatórios.
@EnumSource As constantes de uma enumeração Cada valor de enumeração deve ser exercitado.

Duas regras costumam pegar os iniciantes desprevenidos. Uma anotação de origem colocada em um método `@Test` simples é ignorada silenciosamente, então o método deve conter `@ParameterizedTest`. E um valor vazio sem aspas em `@CsvSource` é lido como nulo, enquanto um valor vazio entre aspas é lido como uma string vazia.

O JUnit As 4 anotações usadas neste artigo são mapeadas no Jupiter da seguinte forma: `@RunWith(Parameterized.class)` torna-se `@ParameterizedTest` mais uma anotação de origem, `@Parameters` torna-se `@MethodSource` ou `@CsvSource`, e `@Before` torna-se `@BeforeEach`. A lista completa está disponível no [link para o artigo]. JUnit anotações tutorial.

Vantagens e limitações dos testes parametrizados

A parametrização não é gratuita. Ela elimina a duplicação, mas também restringe a forma como um teste pode ser escrito, portanto, vale a pena conhecer ambos os lados antes de converter um conjunto de testes existente.

Vantagens

  • Less duplicação: Um dos métodos substitui um bloco de instruções assert quase idênticas, como mostra a primeira captura de tela deste artigo.
  • Cobertura mais barata: Adicionar um caso extremo custa uma linha de dados a mais em vez de uma linha completamente nova. caso de teste método.
  • Relatórios precisos: Cada iteração é relatada separadamente, então o JUnit A visualização identifica exatamente qual linha apresentou falha, em vez de uma falha agregada.
  • Dados centralizados: Os dados de entrada residem em um único método e podem ser posteriormente movidos para um arquivo CSV ou um factory sem alterar as asserções.

Limitações

  • Uma forma de afirmação: Cada linha executa as mesmas verificações, portanto, um cenário que precise de verificações diferentes ainda precisará de seu próprio método de teste.
  • Escopo de nível de classe em JUnit 4: O executor parametriza a classe inteira, portanto, métodos @Test não relacionados nessa classe também são executados uma vez por linha.
  • Relatórios ilegíveis: Sem um modelo de nome, as falhas aparecem como testAirthematicTest[3], que não diz nada sobre os dados que falharam.
  • Dados embutidos volumosos: Grandes arrays podem sobrecarregar a lógica de teste; mova-os para uma fábrica com a anotação `@CsvFileSource` ou `@MethodSource`.

Erros comuns em JUnit Testes parametrizados

A maioria das falhas parametrizadas são erros de inicialização que ocorrem antes da execução de uma única asserção. A tabela abaixo lista as mensagens que aparecem com mais frequência e o que as desencadeia.

Mensagem Causar Fixar
A classe de teste deve ter exatamente um construtor público. A classe não declara nenhum construtor público, ou declara dois. Mantenha um construtor público cujos parâmetros correspondam às colunas de dados.
Não existe um método público de parâmetros estáticos na classe. O método @Parameters não é público estático ou retorna um tipo incorreto. Declare-a como uma coleção pública estática e retorne Arrays.asList(…)
IllegalArgumentException: número incorreto de argumentos Uma linha é mais larga ou mais estreita do que a lista de parâmetros do construtor. Faça com que todos os arrays da Coleção tenham a mesma largura que o construtor.
Erro de configuração: nenhum provedor de argumentos Um teste Jupiter carrega @ParameterizedTest sem nenhuma anotação de origem. Adicione @ValueSource, @CsvSource, @CsvFileSource, @MethodSource ou @EnumSource.
A anotação da fonte parece não fazer nada. O método está anotado com @Test em vez de @ParameterizedTest. Substitua @Test por @ParameterizedTest e importe junit-jupiter-params.

Outra armadilha é o estado compartilhado. Porque JUnit Constrói uma nova instância por linha, qualquer valor armazenado em um campo estático persiste em todas as iterações e um valor escrito pela linha [0] pode alterar silenciosamente o resultado da linha [4]. Mantenha o estado por linha nos campos da instância e redefina os recursos compartilhados no método @Before ou @BeforeEach. Orientações gerais sobre como isolar testes são abordadas em teste de unidade tutorial.

Perguntas Frequentes

TestNG Fornece linhas através de um método @DataProvider referenciado por método de teste, portanto, testes não relacionados na classe não são afetados. JUnit O parâmetro 4 parametriza toda a classe através de seu executor. JUnit A versão 5 elimina essa lacuna com o @ParameterizedTest por método.

Sim. Travas deslizantes portáteis JUnit O tipo 4 aceita `@Parameters(name = “{index}: sum({0},{1})={2}”)` e o tipo Jupiter aceita `@ParameterizedTest(name = “…”). Os marcadores de posição são substituídos em tempo de execução, portanto, um relatório de falha nomeia a linha com problema em vez de mostrar apenas o índice.

Sim. Travas deslizantes portáteis JUnit A versão 4 suporta @Parameter(0) e @Parameter(1) em campos públicos não estáticos, e a classe então depende do construtor padrão. Combinar injeção de campo com um construtor de dados aciona o erro de exatamente um construtor público.

JUnit A versão 4 precisa apenas do artefato JUnit, pois o executor parametrizado já vem incluído nela. JUnit A versão 5 requer o junit-jupiter-params juntamente com o junit-jupiter-api; sem esse artefato, a anotação @ParameterizedTest e todas as anotações de origem falham ao serem resolvidas.

Jupiter fornece @CsvFileSource(resources = “/data.csv”, numLinesToSkip = 1), que lê linhas do classpath de teste. JUnit O número 4 não possui um equivalente integrado, portanto, o método @Parameters deve abrir e analisar o próprio arquivo antes de retornar a Coleção.

In JUnit 4. Pode, mas o executor parametriza a classe inteira, então cada método é executado uma vez por linha de dados. O Jupiter parametriza métodos individuais, então métodos anotados com @Test na mesma classe ainda são executados exatamente uma vez.

Os assistentes de IA leem a assinatura de um método e sugerem linhas de limite, como entradas zero, negativas, máximas e de estouro, que uma tabela escrita à mão geralmente não contempla. RevAnalise cada resultado esperado gerado, pois um modelo pode produzir uma linha plausível com a resposta errada.

Copiloto do GitHub produz o andaime rapidamente, mas frequentemente mistura JUnit 4 e Jupiter importam, e às vezes deixam uma anotação de origem em um método @Test simples. Verifique as importações antes de executar o conjunto de testes.

Resuma esta postagem com: