Testes Unitários com JUnit no Java
Tags: junit, unittest, java, tdd
Published: 2024-03-21 16:28:35

Os testes unitários estão sendo cruciais no meu dia a dia no desenvolvimento de software, garantindo que cada parte do código funcione como esperado. Percebo que no contexto da programação em Java, o JUnit é uma das ferramentas mais populares para escrever e executar testes unitários. Neste post quero explorar os conceitos básicos de testes unitários com JUnit, incluindo a configuração do ambiente de teste e os métodos mais comuns encontrados em testes unitários.

## **Configuração do Ambiente de Teste**

Antes de começar a escrever testes, é necessário configurar o ambiente de teste. Isso geralmente envolve adicionar as dependências do JUnit ao seu projeto. Se você estiver usando Maven ou Gradle, pode adicionar a dependência do JUnit ao seu arquivo `pom.xml` ou `build.gradle`, respectivamente.

**Maven**

Para Maven, adicione o seguinte ao seu `pom.xml`:

```jsx
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>
```

**Gradle**

Para Gradle, adicione a seguinte linha ao seu `build.gradle`:

```jsx
dependencies {
    testImplementation 'junit:junit:4.13.2'
}
```

Quando se trabalha com Spring Boot, uma das vantagens é a facilidade de configuração e execução de testes unitários e de integração. O `spring-boot-starter-test` é um starter que inclui todas as dependências necessárias para testar aplicações Spring Boot, incluindo JUnit, Mockito, AssertJ, entre outras ferramentas úteis para testes. Mas esse é assunto para outro post, que pretendo explorar um pouco mais sobre esse starter.

## **Escrevendo Testes Unitários**

Um teste unitário é uma função que verifica o comportamento de uma parte específica do código, como um método ou uma classe. No JUnit, os testes são escritos como métodos públicos anotados com `@Test`.

**Exemplo de Teste Unitário**

Aqui está um exemplo simples de um teste unitário para uma classe `Calculadora`:

```jsx
import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class CalculadoraTest {

    @Test
    public void testSoma() {
        Calculadora calculadora = new Calculadora();
        int resultado = calculadora.soma(2, 3);
        assertEquals(5, resultado);
    }
}
```

Neste exemplo, o método `testSoma` verifica se o método `soma` da classe `Calculadora` retorna o valor esperado.

## **Métodos Comuns em Testes Unitários**

Aqui está uma lista de métodos comuns que costumo utilizar em meus testes unitários com JUnit, juntamente com uma explicação resumida de cada um:

### **`assertEquals(expected, actual)`**

- **Descrição**: Verifica se dois valores são iguais. Se não forem, o teste falha.
- **Uso**: Útil para comparar valores primitivos, objetos e arrays.

### **`assertTrue(condition)`**

- **Descrição**: Verifica se uma condição é verdadeira. Se não for, o teste falha.
- **Uso**: Útil para verificar a validade de uma expressão booleana.

### **`assertFalse(condition)`**

- **Descrição**: Verifica se uma condição é falsa. Se não for, o teste falha.
- **Uso**: Útil para verificar a invalidade de uma expressão booleana.

### **`assertNull(object)`**

- **Descrição**: Verifica se um objeto é nulo. Se não for, o teste falha.
- **Uso**: Útil para verificar se um objeto não foi inicializado.

### **`assertNotNull(object)`**

- **Descrição**: Verifica se um objeto não é nulo. Se for, o teste falha.
- **Uso**: Útil para verificar se um objeto foi inicializado corretamente.

### **`assertSame(expected, actual)`**

- **Descrição**: Verifica se dois objetos são o mesmo objeto. Se não forem, o teste falha.
- **Uso**: Útil para verificar se duas referências apontam para o mesmo objeto na memória.

### **`assertNotSame(expected, actual)`**

- **Descrição**: Verifica se dois objetos não são o mesmo objeto. Se forem, o teste falha.
- **Uso**: Útil para verificar se duas referências apontam para objetos diferentes na memória.

### **`assertArrayEquals(expected, actual)`**

- **Descrição**: Verifica se dois arrays são iguais. Se não forem, o teste falha.
- **Uso**: Útil para comparar arrays de qualquer tipo.

### **`assertThat(actual, matcher)`**

- **Descrição**: Verifica se um objeto atende a uma condição especificada por um matcher. Se não atender, o teste falha.
- **Uso**: Útil para verificações complexas e legíveis, utilizando a biblioteca Hamcrest para definir matchers.

### **`fail(message)`**

- **Descrição**: Faz o teste falhar imediatamente, com uma mensagem opcional.
- **Uso**: Útil para indicar que um teste não deve ser executado ou para indicar um erro inesperado.

### **`assumeTrue(condition)`**

- **Descrição**: Ignora o teste se a condição for falsa.
- **Uso**: Útil para evitar a execução de testes sob certas condições, como a presença de um recurso específico.

### **`assumeFalse(condition)`**

- **Descrição**: Ignora o teste se a condição for verdadeira.
- **Uso**: Útil para evitar a execução de testes sob certas condições, como a ausência de um recurso específico.

Esses métodos são fundamentais para escrever testes unitários eficazes com JUnit, permitindo que verifiquemos o comportamento do código de maneira clara e concisa.

## JUnit com outras ferramentas

Eh possível integrar o JUnit com outras ferramentas de testes para ampliar a funcionalidade e a eficiência dos testes unitários. Essa integração pode ser feita de várias maneiras, dependendo das necessidades específicas do projeto e das ferramentas desejadas. Aqui estão algumas maneiras comuns de integrar o JUnit com outras ferramentas de testes:

**1. Mocking com Mockito**

Mockito é uma biblioteca popular para criar e configurar objetos fictícios (mocks) em testes unitários. Ela pode ser usada em conjunto com o JUnit para isolar partes do código que estão sendo testadas, permitindo que você teste o comportamento de uma classe ou método sem depender de outras partes do sistema.

**2. Assertions com AssertJ**

AssertJ é uma biblioteca que fornece uma maneira mais legível e expressiva de escrever asserções em testes unitários. Ela pode ser usada em conjunto com o JUnit para melhorar a legibilidade e a clareza dos testes, tornando-os mais fáceis de entender e manter.

**3. Testes de Integração com Spring Test**

Para aplicações Spring Boot, o `spring-boot-starter-test` inclui o Spring Test, que fornece suporte para testes de integração e testes de controle de serviço. O Spring Test pode ser usado em conjunto com o JUnit para testar aplicações Spring Boot de maneira mais eficaz, aproveitando os recursos do Spring para configurar e executar testes.

**4. Testes de Performance com JMeter**

Embora o JMeter seja uma ferramenta separada para testes de performance, ele pode ser integrado com testes unitários escritos com JUnit para realizar testes de performance em aplicações Java. Isso permite que você teste o desempenho de suas aplicações em diferentes cenários e condições.

**5. Testes de Interface do Usuário com Selenium**

Selenium é uma ferramenta para testes de automação de navegadores da web. Embora seja mais comumente usada para testes de interface do usuário (UI), ela pode ser integrada com testes unitários escritos com JUnit para automatizar testes de UI e verificar a funcionalidade da interface do usuário.

**6. Testes de Controle de Versão com Git**

Embora o Git seja uma ferramenta de controle de versão e não uma ferramenta de teste, ele pode ser integrado com o processo de teste para garantir que apenas código que passa por todos os testes unitários seja commitado no repositório. Isso pode ser feito configurando o Git para executar os testes unitários antes de permitir que um commit seja feito.

## **Conclusão**

Os testes unitários estão sendo fundamentais para garantir a qualidade do código e a correção de bugs dos projetos que venho desenvolvendo. O JUnit oferece uma ampla gama de métodos para verificar o comportamento do código, tornando-o uma ferramenta poderosa para testes unitários em Java. Ao escrever testes unitários, é importante cobrir todos os casos de uso possíveis para garantir que o código funcione como esperado em todas as situações.

### Referências:

- https://junit.org/junit5/docs/current/user-guide/
- https://www.baeldung.com/junit-5
- https://www.baeldung.com/java-unit-testing-best-practices