Publicado em
- 4 min read
Testes unitários com @ParameterizedTest no JUnit 5: Escrevendo menos, testando mais
Introdução
“Se você repete código nos testes, está fazendo errado.”
Essa frase pode soar provocativa, mas é exatamente o que acontece quando ignoramos os testes parametrizados no JUnit 5.
Quem já escreveu testes unitários em Java sabe como é comum cair na repetição: testamos valores diferentes, mas o formato do teste é sempre o mesmo. Isso gera mais linhas de código, torna a manutenção cansativa e, muitas vezes, desanima a escrever novos testes.
A boa notícia é que o JUnit 5 oferece uma forma simples e elegante de resolver esse problema: os testes parametrizados. Com o uso de anotações como @ParameterizedTest, @ValueSource, @NullSource, @EmptySource, @EnumSource, é possível escrever menos código, testar mais cenários e deixar tudo mais limpo, expressivo e poderoso.
Neste artigo, vamos aprender na prática como essas anotações funcionam e como podem transformar seus testes em ferramentas muito mais produtivas no dia a dia.
Setup
Utilizaremos as dependências abaixo:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.13.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.13.4</version>
<scope>test</scope>
</dependency>
Porque utilizar testes parametrizados?
Imagine que você precisa validar se uma string não está vazia. A forma tradicional seria escrever vários testes:
@Test
void deveValidarStringComConteudo() {
assertTrue(StringUtils.isNotBlank("Java"));
}
@Test
void deveValidarStringComEspacos() {
assertFalse(StringUtils.isNotBlank(" "));
}
@Test
void deveValidarStringVazia() {
assertFalse(StringUtils.isNotBlank(""));
}
Funciona? Sim. Mas é verboso e difícil de manter.
Com testes parametrizados, escrevemos um único método que roda com vários valores.
Começando com @ParameterizedTest e @ValueSource
A maneira como criamos os testes continua a mesma, mas inserindo anotação @ParameterizedTest, informamos para o teste que daremos algumas entradas para que ele utilize a mesma estrutura, executando uma vez para cada uma.
Os valores informados através das anotações de origem (source), serão passadas através do argumento do método para cada execução.
A anotação @ValueSource permite informar valores primitivos e strings:
@ParameterizedTest
@ValueSource(strings = {"Java", "JUnit", "Spring"})
void deveValidarStringsNaoVazias(String palavra) {
assertTrue(palavra.length() > 0);
}
Aqui, o JUnit executa o mesmo teste para cada valor. Três testes, um método. Bem melhor, não?

Incluindo valores nulos e vazios: @NullSource e @EmptySource
Quer testar cenários com null e strings vazias? Simples!
A anotação @NullSource passa nulo para o argumento do método, enquanto @EmptySource passa uma String vazia:
@ParameterizedTest
@NullSource
@EmptySource
@ValueSource(strings = {" ", "\t"})
void deveRetornarFalsoParaStringsInvalidas(String texto) {
assertFalse(StringUtils.isNotBlank(texto));
}
Com isso, cobrimos:
- null
- String vazia ""
- Strings com espaço ou tabulação
Um único teste cobre vários casos críticos!
Testando Enums com @EnumSource
Enums são comuns em validações de negócio.
Considerando que temos o enum:
enum Status {
ATIVO, INATIVO, PENDENTE
}
Quer validar que todos os status não são nulos?
@ParameterizedTest
@EnumSource(Status.class)
void deveValidarStatusNaoNulo(Status status) {
assertNotNull(status);
}
E se quiser filtrar? Ex.: apenas ATIVO e INATIVO:
@ParameterizedTest
@EnumSource(value = Status.class, names = { "ATIVO", "INATIVO"})
void deveValidarApenasStatusPermitidos(Status status) {
assertTrue(status == Status.ATIVO || status == Status.INATIVO);
}
Quando os dados são complexos: @MethodSource
Para cenários mais elaborados, como múltiplos parâmetros, usamos @MethodSource. Essa anotação permite informar o nome do método que irá fornecer as entradas para realização dos testes, perceba que nesse cenário, temos mais de um argumento no método:
@ParameterizedTest
@MethodSource("fornecerNumerosParaSoma")
void deveSomarNumerosCorretamente(int a, int b, int esperado) {
assertEquals(esperado, a + b);
}
static Stream < Arguments > fornecerNumerosParaSoma() {
return Stream.of(
Arguments.of(1, 2, 3),
Arguments.of(10, 5, 15),
Arguments.of(-1, 1, 0)
);
}
Agora temos cenários dinâmicos e expressivos, sem duplicação.
Dicas para testes parametrizados de qualidade
- Use nomes de métodos descritivos;
- Cuidado com cenários excessivos (evite datasets gigantes);
- Combine @NullSource e @EmptySource para inputs frágeis;
- Prefira @MethodSource para dados complexos ou dependentes;
Conclusão
Escrever testes unitários não precisa ser sinônimo de repetição e código verboso. Como vimos, os testes parametrizados do JUnit 5 são uma forma prática e elegante de simplificar esse processo.
Com anotações como @ValueSource, @NullSource, @EmptySource, @EnumSource, conseguimos validar vários cenários de forma clara, reduzindo a duplicação e aumentando a cobertura dos testes.
No fim das contas, vale lembrar da frase que guiou este artigo: “Se você repete código nos testes, está fazendo errado.”
Ao adotar os testes parametrizados, você ganha produtividade, clareza e confiança no seu código — três elementos fundamentais para qualquer desenvolvedor que busca qualidade e eficiência no dia a dia.
👉 Agora é com você: que tal aplicar um @ParameterizedTest no seu próximo teste e sentir na prática essa diferença? E se este conteúdo te ajudou, compartilhe com sua equipe para espalhar boas práticas no desenvolvimento.
🔗 Repositório com projeto completo
Acesse o repositório com o projeto completo pronto para rodar:
👉 https://github.com/LuizEduardoBilotta/demo—lebilotta-parameterizedTest