Este repositório consolida o aprendizado prático em testes automatizados no backend, evoluindo desde fundamentos com Java puro até a aplicação em uma arquitetura real utilizando Spring Boot.
Mais do que validar código, o foco está em compreender como projetar software testável, aplicar boas práticas e garantir qualidade de forma consistente — competências essenciais no desenvolvimento backend profissional.
Projeto voltado para o entendimento dos conceitos essenciais de testes unitários com JUnit 5, sem abstrações de frameworks.
Foco em:
- Testar métodos de forma isolada
- Escrever testes previsíveis e replicáveis
- Validar regras de negócio
- Trabalhar com cenários positivos e negativos
Projeto baseado em uma API REST com arquitetura em camadas.
Foco em:
- Testes de Repository, Service e Controller
- Testes de integração
- Uso de Mockito e MockMvc
- Simulação de dependências
Validam unidades isoladas de código (geralmente métodos), sem dependências externas.
- Não acessam banco, API ou arquivos
- São rápidos
- Validam regras de negócio
Validam a comunicação entre componentes da aplicação.
Exemplo:
- Controller → Service → Repository
Validam o comportamento do sistema do ponto de vista do usuário.
- Detectar erros rapidamente
- Servir como documentação viva
- Reduzir custo de manutenção
- Melhorar o design do código
- Aumentar a confiabilidade
O TDD é uma abordagem onde o desenvolvimento é guiado pelos testes.
Você começa definindo o comportamento esperado antes de implementar.
@Test
void withdrawShouldDecreaseBalance() {
Account acc = new Account(100.0);
acc.withdraw(50.0);
Assertions.assertEquals(50.0, acc.getBalance());
}👉 Nesse momento, o teste falha porque o comportamento ainda não existe (ou está incorreto).
Agora você escreve apenas o código suficiente para fazer o teste passar:
public void withdraw(double amount) {
balance -= amount;
}👉 Sem otimizações, apenas o necessário.
Agora você melhora o código:
- validações
- organização
- legibilidade
👉 Com a segurança de que os testes vão indicar se algo quebrou.
- Primeiro define o comportamento
- Depois implementa
- Por fim melhora o código com segurança
Um teste deve ser legível como uma frase.
<AÇÃO> should <EFEITO> [when <CENÁRIO>]
withdrawShouldThrowExceptionWhenInsufficientBalance- Ação →
withdraw - Efeito →
shouldThrowException - Cenário →
whenInsufficientBalance
👉 Tradução:
“Saque deve lançar exceção quando saldo for insuficiente”
✔️ O nome já explica o comportamento sem precisar abrir o código.
Estrutura padrão para organizar testes:
- Arrange → preparar dados
- Act → executar ação
- Assert → validar resultado
@Test
void depositShouldIncreaseBalance() {
// Arrange
Account acc = new Account(0.0);
// Act
acc.deposit(100.0);
// Assert
Assertions.assertEquals(100.0, acc.getBalance());
}- Um teste não depende de outro
- Não depende de ordem de execução
- Testa apenas um cenário
Cada teste deve validar apenas um comportamento.
❌ Evitar:
- múltiplos cenários no mesmo teste
- lógica complexa dentro do teste
Um teste deve sempre produzir o mesmo resultado para os mesmos dados.
Evitar:
- uso de
LocalDate.now() - valores aleatórios
- dependência de ambiente externo
Para escrever bons testes unitários, é essencial conseguir isolar a classe que está sendo testada.
public class OrderService {
private PaymentService paymentService = new PaymentService();
public void process() {
paymentService.pay();
}
}👉 Problema:
- A classe cria sua própria dependência
- Não conseguimos controlar o comportamento no teste
public class OrderService {
private PaymentService paymentService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public void process() {
paymentService.pay();
}
}@Mock
private PaymentService paymentService;
@InjectMocks
private OrderService orderService;when(paymentService.pay()).thenReturn(true);- Classe desacoplada
- Teste isolado
- Controle total dos cenários
“Não deixe a classe criar suas dependências — receba elas de fora.”
Framework principal para testes.
@Test
void example() {
Assertions.assertEquals(expected, actual);
}Assertions.assertThrows(Exception.class, () -> {
method();
});- Testa acesso ao banco
- Usa
@DataJpaTest - Rollback automático
- Teste unitário
- Uso de Mockito
- Isolamento da regra de negócio
- Testes com
MockMvc - Não sobe servidor
- Valida HTTP (status e resposta)
- Usa
@SpringBootTest - Testa fluxo completo
Utilizado para simular dependências.
when(service.findById(1L)).thenReturn(product);verify(repository).save(entity);| Situação | Uso |
|---|---|
| Sem Spring | @Mock |
| Com Spring | @MockBean |
Evita repetição nos testes:
@BeforeEach@AfterEach
- Java
- JUnit 5
- Spring Boot
- Maven
- Mockito
- MockMvc
Os conceitos aplicados aqui refletem práticas reais de desenvolvimento backend:
- Escrita de testes confiáveis
- Isolamento de dependências
- Uso de mocks
- Testes em múltiplas camadas
- Garantia de qualidade contínua
👉 Testes não são apenas validação — são parte essencial do design da aplicação.
Este projeto representa a evolução de:
- Código funcional → código testável
- Testes simples → testes estruturados
- Conhecimento teórico → aplicação prática
Albert Silva de Jesus
Desenvolvedor Backend Java | Spring Boot