O que é Junit? E Como Começar com Testes Unitários em Java?

Olá Programador! No mundo do desenvolvimento de software, a garantia da qualidade é fundamental. Testar o código é uma prática essencial para garantir que um sistema funcione corretamente. É nesse cenário que entra o JUnit, uma ferramenta amplamente utilizada para automatizar testes em Java.

Antes de entendermos o que são testes, precisamos entender primeiro, por que testar?

No mundo da programação, os testes unitários são como o alicerce de um prédio: essenciais para garantir a robustez e a estabilidade de um software. Eles são pequenos testes automatizados, focados em partes individuais do código, que verificam se determinadas funções ou métodos estão funcionando como esperado.

o que é junit?

O que é JUnit?

O JUnit é um renomado framework de testes unitários utilizado por desenvolvedores Java para automatizar e simplificar o processo de verificação de código. Desde sua criação, ele se tornou uma peça fundamental no arsenal de ferramentas para testes de software em Java.

Em termos simples, o JUnit é uma estrutura que permite a criação e execução de testes automatizados em código Java. Ele facilita a realização de testes unitários, que são testes focados em partes individuais, ou unidades, do código, como métodos, classes ou pequenos conjuntos de funcionalidades.

O JUnit foi desenvolvido por Kent Beck e Erich Gamma nos finais da década de 1990. Desde então, passou por várias iterações e melhorias, com contribuições significativas da comunidade de desenvolvedores Java. Sua evolução resultou no surgimento de diferentes versões, sendo o JUnit 4 e o JUnit 5 as mais notáveis.

  • JUnit 4: Foi a versão padrão por um longo período. Oferece uma variedade de funcionalidades para escrever e executar testes de maneira eficiente, utilizando anotações como @Test para identificar métodos de teste e assertivas para verificar resultados esperados.
  • JUnit 5: É uma versão mais recente e poderosa, introduzindo novos recursos e melhorias significativas em comparação com seu antecessor. Apresenta suporte aprimorado para lambdas, extensibilidade, suporte a novas anotações e arquitetura mais modular.

Como o JUnit é usado?

Usar o JUnit é relativamente simples. Assim como eu, nós desenvolvedores podemos criar classes de teste que contêm métodos para verificar se partes específicas do código funcionam corretamente. O framework fornece anotações como @Test para identificar métodos de teste, além de assertivas como assertEquals, assertTrue, assertFalse, entre outras, para verificar se os resultados obtidos são os esperados.

Exemplo com uma Classe Calculadora

public class Calculadora {

    public int somar(int a, int b) {
        return a + b;
    }

    public int subtrair(int a, int b) {
        return a - b;
    }

    public int multiplicar(int a, int b) {
        return a * b;
    }

    public double dividir(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException("Divisão por zero não permitida!");
        }
        return (double) a / b;
    }

    public double potencia(double base, double expoente) {
        return Math.pow(base, expoente);
    }

    public double raizQuadrada(double a) {
        if (a < 0) {
            throw new IllegalArgumentException("Não é possível calcular raiz quadrada de número negativo!");
        }
        return Math.sqrt(a);
    }
}

Agora que temos uma classe Java, precisamos realizar alguns testes unitários, por que nada garante que todos esses métodos da classe estão funcionando corretamente certo?

Exemplo de Teste Unitário:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class CalculadoraTest {

    private Calculadora calculadora;

    @BeforeEach
    public void setUp() {
        calculadora = new Calculadora();
    }

    @Test
    public void testSomar() {
        int resultado = calculadora.somar(5, 3);
        assertEquals(8, resultado);
    }

    @Test
    public void testSubtrair() {
        int resultado = calculadora.subtrair(10, 4);
        assertEquals(6, resultado);
    }

    @Test
    public void testMultiplicar() {
        int resultado = calculadora.multiplicar(7, 3);
        assertEquals(21, resultado);
    }

    @Test
    public void testDividir() {
        double resultado = calculadora.dividir(20, 5);
        assertEquals(4, resultado);
    }

    @Test
    public void testDividirPorZero() {
        assertThrows(ArithmeticException.class, () -> {
            calculadora.dividir(10, 0);
        });
    }

    @Test
    public void testPotencia() {
        double resultado = calculadora.potencia(2, 3);
        assertEquals(8, resultado);
    }

    @Test
    public void testRaizQuadrada() {
        double resultado = calculadora.raizQuadrada(25);
        assertEquals(5, resultado);
    }

    @Test
    public void testRaizQuadradaDeNumeroNegativo() {
        assertThrows(IllegalArgumentException.class, () -> {
            calculadora.raizQuadrada(-9);
        });
    }
}

Neste exemplo, a classe CalculadoraTest contém vários métodos de teste utilizando o JUnit. Cada método de teste está testando um método correspondente da classe Calculadora, como somar, subtrair, multiplicar, dividir, potência e raiz quadrada.

Para cada método de teste, são utilizadas as assertivas do JUnit, como assertEquals, para verificar se os resultados obtidos são iguais aos resultados esperados para diferentes operações matemáticas.

Entretanto, são lançadas exceções (ArithmeticException IllegalArgumentException) em casos de divisão por zero ou tentativa de calcular a raiz quadrada de um número negativo, respectivamente.

Os métodos na classe de teste CalculadoraTest foram expandidos para verificar o comportamento desses métodos em diferentes situações, utilizando as assertivas do JUnit para validar os resultados esperados ou exceções lançadas.

Este exemplo visa demonstrar como os testes unitários podem ser utilizados para verificar o comportamento de diferentes métodos em uma classe, garantindo que funcionem conforme o esperado em diferentes cenários.

Principais Anotações do JUnit

Vamos conhecer uma lista com 6 das anotações mais comuns do JUnit, utilizada nas maiorias dos testes unitários:

1º @Test

a anotação @Test é uma das anotações fundamentais do JUnit e desempenha um papel crucial na identificação de métodos que são casos de teste. Ela é usada para marcar um método como um teste unitário e indica ao JUnit que esse método deve ser executado como parte dos testes automatizados.

@Test
public void testSomeMethod() {
    // Lógica do teste
}

2º @BeforeEach

A anotação @BeforeEach indica que um método deve ser executado antes de cada método de teste na classe. É útil para configurações que devem ser realizadas antes de cada teste.

Por exemplo, se queremos que determinado código ou função seja executada primeiramente antes mesmos dos testes, é nessa hora que faz sentido utilizarmos essa anotação.

@BeforeEach
public void setUp() {
    // Configuração prévia para os testes
}

3º @AfterEach

A anotação @AfterEach é uma das anotações de ciclo de vida dos testes disponíveis no JUnit. Ela é utilizada para indicar que um determinado método deve ser executado após a conclusão de cada método de teste (@Test) na classe de teste. Esse método é útil para realizar ações de limpeza, liberar recursos ou redefinir o estado do ambiente após a execução de cada teste individual.

Ela é frequentemente utilizada para reverter alterações realizadas durante um teste específico, restaurar o estado inicial de objetos, fechar conexões de banco de dados temporárias, limpar estruturas de dados utilizadas durante o teste, ou qualquer outra ação necessária para garantir que cada teste comece com um estado consistente.

@AfterEach
public void tearDown() {
    // Limpeza após os testes
}

4º @BeforeAll

A anotação @BeforeAll indica que um método estático deve ser executado antes de todos os métodos de teste na classe. É usado para configurações que devem ser realizadas apenas uma vez antes de todos os testes.

@BeforeAll
public static void setUpClass() {
    // Configuração prévia para todos os testes na classe
}

5º @AfterAll

a anotação @AfterAll é uma das anotações de ciclo de vida dos testes no JUnit e é usada para indicar que um método estático deve ser executado após a conclusão de todos os métodos de teste na classe.

Assim como @BeforeAll, é executado uma única vez, garantindo que operações específicas de finalização sejam realizadas após todos os testes. Isso ajuda a manter a independência entre os casos de teste e garante que o ambiente seja restaurado para um estado predefinido após a execução de todos os testes.

@AfterAll
public static void tearDownClass() {
    // Limpeza após todos os testes na classe
}

6º @DisplayName

A anotação @DisplayName é uma funcionalidade do JUnit que permite atribuir nomes personalizados e descritivos aos métodos de teste. Ela não afeta o funcionamento do teste em si, mas melhora significativamente a legibilidade e compreensão dos relatórios de testes.

@Test
@DisplayName("Olá esse é uma descrição de um Teste para o Post do portal virandoprogramador.com.br!")
public void testSomaNumerosPositivos() {
    // Lógica do teste
}

Por que eu devo testar o meu Código?

Imagine um engenheiro construindo uma ponte. Antes de liberar essa estrutura para o tráfego, é essencial garantir que ela seja segura e capaz de suportar a carga que receberá.

Da mesma forma, no desenvolvimento de software, os testes desempenham um papel crucial. Eles são a garantia de que o código desenvolvido é robusto, confiável e atende aos requisitos esperados. Separei 3 pontos importantes do motivo de testar os códigos feitos, independente da Linguagem de Programação:

1. Garantia de Qualidade

Os testes unitários têm um papel fundamental na garantia da qualidade do software. Eles são projetados para verificar se cada unidade isolada de código (como uma função, método ou classe) está produzindo os resultados corretos. Isso significa que mesmo pequenas partes do código são submetidas a testes rigorosos, o que reduz a chance de erros passarem despercebidos.

2. Detecção Rápida de Problemas

Ao escrever testes unitários, os desenvolvedores têm a oportunidade de identificar problemas de imediato. Imagine encontrar um bug em uma função que você escreveu há semanas. Com testes unitários adequados, é mais provável que você detecte e corrija o problema imediatamente, pois os testes agem como um sistema de alerta antecipado.

3. Manutenção e Refatoração

À medida que um código evolui, é comum realizar atualizações, adicionar novos recursos ou refatorar partes antigas. Sem testes unitários, essas mudanças podem introduzir inadvertidamente erros em outras áreas do código.

No entanto, quando os testes estão em vigor, eles atuam como um escudo de proteção, permitindo que os desenvolvedores façam alterações com mais confiança, sabendo que podem verificar imediatamente se nada foi quebrado.

Resumindo sobre o JUnit

No universo do desenvolvimento de software, a garantia da qualidade é indispensável para criar aplicações confiáveis, livres de falhas e que atendam às expectativas dos usuários.

Nesse contexto, o JUnit se mostra adequado como uma das ferramentas mais valiosas para os desenvolvedores, especialmente na esfera do Java, oferecendo uma estrutura robusta e eficaz para a criação e execução de testes unitários.

Os testes unitários são uma pedra angular no desenvolvimento de software, permitindo que nós programadores avaliem o comportamento de pequenas partes do código, conhecidas como unidades, de forma isolada.

Esses testes verificam se cada unidade funciona conforme o esperado, contribuindo para a detecção precoce de erros e fornecendo um ambiente seguro para modificações no código sem comprometer sua funcionalidade.

Flexibilidade

A flexibilidade desse Framework permite a execução de testes de forma rápida e repetida. Isso é particularmente valioso no contexto do desenvolvimento ágil, onde as iterações são frequentes e as mudanças no código são comuns.

A capacidade de executar testes de forma rápida e confiável oferece aos desenvolvedores feedback imediato sobre as possíveis falhas introduzidas por alterações recentes, permitindo correções ágeis e evitando que problemas se propaguem para outras partes do sistema.

5/5 - (1 vote)

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *