Testes - ecosif-auth
Este documento descreve como escrever e executar testes no ecosif-auth.
Estrutura de Testes
Localização
Os testes devem estar no mesmo pacote que o código testado, no diretório src/test/java:
src/
├── main/
│ └── java/
│ └── io/ecosif/auth/
│ └── controller/
│ └── AuthController.java
└── test/
└── java/
└── io/ecosif/auth/
└── controller/
└── AuthControllerTest.java
Tipos de Testes
1. Testes Unitários
Testam classes isoladamente, usando mocks para dependências.
Exemplo: Teste de Service
package io.ecosif.auth.service;
import io.ecosif.auth.model.User;
import io.ecosif.auth.repository.UserRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class UserServiceImplTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserServiceImpl userService;
@Test
void should_ReturnUser_When_UsernameExists() {
// Given
String username = "test@example.com";
User expectedUser = new User();
expectedUser.setUsername(username);
expectedUser.setName("Test User");
when(userRepository.findByUsername(username))
.thenReturn(expectedUser);
// When
User result = userService.findUserByUsername(username);
// Then
assertThat(result).isNotNull();
assertThat(result.getUsername()).isEqualTo(username);
assertThat(result.getName()).isEqualTo("Test User");
verify(userRepository, times(1)).findByUsername(username);
}
@Test
void should_ReturnNull_When_UsernameNotExists() {
// Given
String username = "nonexistent@example.com";
when(userRepository.findByUsername(username))
.thenReturn(null);
// When
User result = userService.findUserByUsername(username);
// Then
assertThat(result).isNull();
verify(userRepository, times(1)).findByUsername(username);
}
}
2. Testes de Integração
Testam a interação entre múltiplos componentes.
Exemplo: Teste de Controller com MockMvc
package io.ecosif.auth.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.ecosif.auth.dto.LoginRequest;
import io.ecosif.security.jwt.TokenProvider;
import io.ecosif.auth.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
@AutoConfigureMockMvc
class AuthControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private UserService userService;
@Test
void should_ReturnBadRequest_When_UsernameIsEmpty() throws Exception {
LoginRequest request = new LoginRequest();
request.setUsername("");
request.setPassword("password");
mockMvc.perform(post("/api/auth/signin")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isBadRequest());
}
}
3. Testes de Repositório
Testam acesso a dados usando banco em memória ou banco de teste.
Exemplo: Teste de Repository
package io.ecosif.auth.repository;
import io.ecosif.auth.model.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest
class UserRepositoryTest {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository userRepository;
@Test
void should_FindUser_When_UsernameExists() {
// Given
User user = new User();
user.setUsername("test@example.com");
user.setName("Test User");
user.setPassword("password");
user.setActive(true);
entityManager.persistAndFlush(user);
// When
User found = userRepository.findByUsername("test@example.com");
// Then
assertThat(found).isNotNull();
assertThat(found.getUsername()).isEqualTo("test@example.com");
}
}
Executando Testes
Todos os Testes
mvn test
Teste Específico
mvn test -Dtest=AuthControllerTest
Classe Específica
mvn test -Dtest=UserServiceImplTest
Com Cobertura
mvn test jacoco:report
Relatório disponível em: target/site/jacoco/index.html
Configuração de Testes
application-test.yml
Crie um arquivo src/test/resources/application-test.yml:
spring:
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password:
jpa:
hibernate:
ddl-auto: create-drop
show-sql: true
app:
auth:
tokenSecret: test-secret-key-for-testing-only-minimum-64-characters-long
tokenExpirationMsec: 1800000
logging:
level:
root: INFO
io.ecosif.auth: DEBUG
Perfil de Teste
Use @ActiveProfiles("test") nos testes:
@SpringBootTest
@ActiveProfiles("test")
class AuthControllerIntegrationTest {
// ...
}
Boas Práticas
1. Nomenclatura
Use nomes descritivos:
@Test
void should_ReturnUser_When_UsernameExists() {
// ...
}
@Test
void should_ThrowException_When_UsernameIsNull() {
// ...
}
2. Estrutura AAA
Organize testes em Arrange, Act, Assert:
@Test
void should_ReturnUser_When_UsernameExists() {
// Arrange (Given)
String username = "test@example.com";
User expectedUser = new User();
// ...
// Act (When)
User result = userService.findUserByUsername(username);
// Assert (Then)
assertThat(result).isNotNull();
// ...
}
3. Isolamento
Cada teste deve ser independente:
@BeforeEach
void setUp() {
// Reset mocks ou estado antes de cada teste
}
4. Mocks
Use mocks para dependências externas:
@Mock
private UserRepository userRepository;
@InjectMocks
private UserServiceImpl userService;
5. Assertions
Use AssertJ para assertions mais legíveis:
import static org.assertj.core.api.Assertions.assertThat;
assertThat(result).isNotNull();
assertThat(result.getUsername()).isEqualTo("test@example.com");
assertThat(list).hasSize(2).contains("item1");
Testes de Segurança
Teste de Autenticação
@Test
void should_RequireAuthentication_ForProtectedEndpoint() throws Exception {
mockMvc.perform(get("/api/admin/docker-logs?service=ecosif-auth"))
.andExpect(status().isUnauthorized());
}
Teste com Token Válido
@Test
void should_AllowAccess_When_ValidToken() throws Exception {
// Criar token JWT válido
String token = createValidToken();
mockMvc.perform(get("/api/admin/docker-logs?service=ecosif-auth")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk());
}
Cobertura de Testes
Metas de Cobertura
- Linhas: > 80%
- Branches: > 75%
- Métodos: > 80%
- Classes: > 80%
Verificar Cobertura
mvn test jacoco:report
Troubleshooting
Testes Falhando
- Verifique os logs de erro
- Certifique-se de que todas as dependências estão mockadas
- Verifique se o banco de teste está configurado corretamente
Testes Lentos
- Use mocks ao invés de integrações reais quando possível
- Use banco em memória (H2) para testes de repositório
- Evite testes desnecessários de integração