Testes em Java: Unit, Integration, E2E em nível avançado

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Testes em Java: Unit, Integration, E2E — Nível Avançado



No desenvolvimento Java moderno, testar não é apenas uma formalidade, mas uma prática fundamental que garante a estabilidade e previsibilidade do código. Testes básicos, como simples @Test com Assert.assertEquals, há muito deram lugar a estratégias complexas de múltiplas camadas. Neste artigo, exploraremos técnicas avançadas para cada nível da pirâmide de testes: Unit, Integration e End-to-End (E2E). Você aprenderá a escrever testes sustentáveis, rápidos e confiáveis que transformarão seu código em um mecanismo bem ajustado.



1. Testes Unit Avançados: Mocks, Stubs e Parametrização



Testes Unit verificam um pedaço isolado de código (geralmente uma classe ou método). Em nível avançado, vamos além de cenários simples para interações complexas e casos limite. A ferramenta chave aqui é a biblioteca Mockito.



1.1. Uso de ArgumentCaptor e respostas complexas (Answer)



Frequentemente, é necessário não apenas verificar se um método foi chamado, mas quais argumentos foram passados para ele. Para isso, usamos ArgumentCaptor.



// Exemplo: Verificar se a mensagem correta foi enviada ao serviço@ExtendWith(MockitoExtension.class)public class NotificationServiceTest {    @Mock    private EmailSender emailSender;    @InjectMocks    private NotificationService notificationService;

@Test void shouldSendEmailWithCorrectContent() { // Arrange User user = new User("test@example.com", "Test User"); // Act notificationService.sendWelcomeEmail(user); // Assert ArgumentCaptor<EmailMessage> captor = ArgumentCaptor.forClass(EmailMessage.class); verify(emailSender).send(captor.capture()); EmailMessage capturedMessage = captor.getValue(); assertEquals("test@example.com", capturedMessage.getTo()); assertTrue(capturedMessage.getBody().contains("Test User")); }}


Para criar respostas dinâmicas com base nos dados de entrada, use a interface Answer:



@Testvoid testDynamicResponse() {    when(dataRepository.findById(anyLong())).thenAnswer(invocation -> {        Long id = invocation.getArgument(0);        return new DataEntity(id, "Entity with ID: " + id);    });    assertEquals("Entity with ID: 5", dataService.getDataById(5L).getName());}


1.2. Testes Parametrizados (JUnit 5)



A parametrização permite executar o mesmo teste com diferentes conjuntos de dados, evitando duplicação de código. O JUnit 5 oferece anotações poderosas, como @CsvSource e @MethodSource.



@ParameterizedTest@CsvSource({    "10, 20, 30",    "0, 0, 0",    "-5, 5, 0"})void testSum(int a, int b, int expectedSum) {    Calculator calculator = new Calculator();    assertEquals(expectedSum, calculator.add(a, b));}


2. Testes de Integração: Trabalhando com Banco de Dados e Serviços Externos



Testes de integração verificam a interação entre componentes do sistema, por exemplo, com um banco de dados real ou filas. O principal desafio é gerenciar o estado do ambiente. É aqui que o Testcontainers entra em ação.



2.1. Testcontainers para Banco de Dados Isolado



O Testcontainers sobe contêineres Docker com o software necessário (PostgreSQL, Redis, Kafka) durante os testes, garantindo limpeza e reprodutibilidade.



@SpringBootTest@Testcontainersclass UserRepositoryIntegrationTest {

@Container static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15") .withDatabaseName("testdb") .withUsername("test") .withPassword("test");

@DynamicPropertySource static void configureProperties(DynamicPropertyR

Blogs

Book Recommendations