Curso JUnit: #3 - Evoluindo nossos testes com o JUnit

Depois de ter entendido o que são testes, qual a sua importância para o desenvolvimento de softwares e depois de criar seu primeiro teste com o JUnit, vamos evoluir em nossa jornada e cobrir mais cenários de testes para garantir que nossa classe funciona corretamente.

Se analisarmos novamente nossas regras de negócio veremos que duas delas dizem:

  • "Não deve ser possível gerar uma senha com menos de 4 digitos"

  • "Não deve ser possível gerar uma senha com mais de 100 digitos"

Porém, nosso código como está hoje permite que sejam geradas senhas de qualquer tamanho, inclusive com 0 dígitos. Precisamos então corrigir isso.

public String gerarSenhaNumerica(int tamanho) throws Exception {

    if (tamanho < 4 || tamanho > 100) {
        throw new Exception("Só é possível gerar senhas com comprimento entre 4 e 100 digitos");
    }

    String senha = "";
    Random random = new Random();

    int MAIOR_VALOR_POSSIVEL = 9;

    for (int i = 0; i < tamanho; i++) {
        int numeroAleatorio = random.nextInt(MAIOR_VALOR_POSSIVEL + 1);
        senha = senha.concat(String.valueOf(numeroAleatorio));
    }

    return senha;

}

Perceba que agora implementamos um bloco de código que garante o tamanho informado deve ser maior ou igual a 4 e menor ou igual a 100.

Com isso, precisamos agora atualizar nosso arquivo de teste informando que esse método pode gerar uma Exception.

@Test
@DisplayName("Deve ser possível gerar uma senha numérica com 8 digitos")
public void testGerarSenhaNumericaComOitoDigitos() throws Exception {
    // ...
}

O código continua funcionando corretamente, e o teste passa sem nenhum problema, porém precisamos escrever novos testes para garantir que essas novas regras de negócio foram satisfeitas.

@Test
@DisplayName("Deve lançar uma Exception ao tentar gerar uma senha numérica com tamanho inválido")
public void testLancarUmaExceptionQuandoTamanhoMenorQueQuatro() throws Exception {

    // Arrange
    int tamanho = 2;
    GeradorDeSenhas geradorDeSenhas = new GeradorDeSenhas();

    // Act
    Executable executable = () -> geradorDeSenhas.gerarSenhaNumerica(tamanho);

    // Assert
    Assertions.assertThrows(Exception.class, executable);

}

Prontinho, agora temos um teste que garante que ao informar um valor inválido o método lançará uma Exception, mas... Será que de fato eu tenho essa garantia com esse código? E se informar 3 será que vai lançar essa Exception? E se eu informar 150 será que lançará essa Exception?

Um valor fixo desse não será o suficiente para termos essa garantia, logo, precisaríamos escrever vários testes para cobrir esses cenários, o que se tornaria impraticável. Pensando nisso o JUnit trouxe uma annotation bem interessante para resolver esse "problema".

Vamos modificar um pouco o nosso teste

@ParameterizedTest
@ValueSource(ints = { -1, 0, 1, 2, 3, 101, 150, 1000 })
@DisplayName("Deve lançar uma Exception ao tentar gerar uma senha numérica com tamanho inválido")
public void testLancarUmaExceptionQuandoTamanhoInvalido(int tamanho) throws Exception {

    // Arrange
    GeradorDeSenhas geradorDeSenhas = new GeradorDeSenhas();

    // Act
    Executable executable = () -> geradorDeSenhas.gerarSenhaNumerica(tamanho);

    // Assert
    Assertions.assertThrows(Exception.class, executable);

}

Aproveitei e mudei também o DisplayName e o nome do método para fazer mais sentido com o novo cenário.

Ao executar esse teste o resultado será:

Ou seja, ao invés de executar o método apenas uma vez, esse método será executado 8 vezes, com 8 valores diferentes.

Vamos agora entender cada parte das alterações realizadas

@ParameterizedTest
@ValueSource(ints = { -1, 0, 1, 2, 3, 101, 150, 1000 })
@DisplayName("Deve lançar uma Exception ao tentar gerar uma senha numérica com tamanho inválido")

A annotation @Test foi substituída pela annotation @ParameterizedTest. Isso indica ao JUnit que o parâmetro que será informado no método a seguir receberá cada um dos valores da lista informada em @ValueSource.

public void testLancarUmaExceptionQuandoTamanhoInvalido(int tamanho) throws Exception { }

O método que não recebia nenhum parâmetro agora recebe um parâmetro inteiro conforme explicado acima

E por fim, a variável tamanho, presente no corpo do método, foi removida.

int tamanho = 8;

Vamos agora propositalmente gerar um erro para vermos como o JUnit se comporta.

Abra a sua classe GeradorDeSenhas, remova temporariamente o bloco abaixo

if (tamanho < 4 || tamanho > 100) {
    throw new Exception("Só é possível gerar senhas com comprimento entre 4 e 100 digitos");
}

Ao executar nosso teste a saída será um pouco diferente agora

Perceba que o nosso primeiro método de teste continua funcionando, mas o segundo método parou de funcionar. Ou seja, com testes unitário você se sente mais seguro para refatorar seu código, visto que se você mexer em algo que não deveria, o teste vai quebrar. 🙂

No próximo post vamos evoluir mais nossa camada de testes e conhecer mais alguns detalhes do JUnit, espero vocês lá.