Projeto | Diagrama | Tipos de Testes | Construir | Executar | Tecnologias
SW-PLANET-API é um serviço web que provê dados sobre a franquia de Star Wars, mais especificamente sobre os planetas que
aparecem nos filmes. Esse projeto foi elaborado durante o curso Testes Automatizados na Prática com Spring Boot,
em que o foco foi a criação de testes automatizados.
Algumas classes foram criadas para separar adequadamente as suas funções e também facilitar a leitura da estrutura:
A classe Planet representa um planeta no universo de Star Wars. Ela é responsável por armazenar informações essenciais
sobre um planeta, incluindo seu nome, clima e terreno. Esta classe está mapeada para a tabela planets no banco de dados e utiliza a especificação JPA para gerenciar a persistência dos dados.
id(Long): Identificador único do planeta, gerado automaticamente pelo banco de dados.name(String): Nome do planeta. Esse campo é obrigatório e deve ser único.climate(String): Descrição do clima do planeta. Campo obrigatório.terrain(String): Descrição do terreno do planeta. Campo obrigatório.
- Construtor Padrão: Utilizado para criar uma instância vazia de
Planet. - Construtor com Clima e Terreno: Permite criar uma instância de
Planetespecificando apenas o clima e o terreno. - Construtor com Nome, Clima e Terreno: Permite criar uma instância de
Planetespecificando o nome, o clima e o terreno. - Construtor com ID, Nome, Clima e Terreno: Utilizado para criar uma instância de
Planetcom todos os atributos definidos, incluindo o ID.
getId() / setId(Long id): Obtém/Define o identificador do planeta.getName() / setName(String name): Obtém/Define o nome do planeta.getClimate() / setClimate(String climate): Obtém/Define o clima do planeta.getTerrain() / setTerrain(String terrain): Obtém/Define o terreno do planeta.equals(Object obj): Sobrescrito para comparar dois objetosPlanetcom base em todos os atributos.toString(): Gera uma representação textual do objetoPlanet.
@Entity: Indica que a classe é uma entidade JPA que será mapeada para uma tabela no banco de dados.@Table(name = "planets"): Especifica o nome da tabela no banco de dados.@Id: Denota o campoidcomo a chave primária.@GeneratedValue(strategy = GenerationType.IDENTITY): Define a estratégia de geração do identificador.@NotEmpty: Valida que os camposname,climate, eterrainnão podem ser nulos ou vazios.@Column: Configura os detalhes das colunas no banco de dados, comonullable = falseeunique = truepara o camponame.@ExcludeFromJacocoGeneratedReport: Exclui o métodotoString()da cobertura de testes gerada pelo Jacoco.
A classe Planet pode ser testada usando as seguintes tecnologias:
- Spring Boot Test: Para o contexto geral de teste.
- JUnit 5: Para criação e execução dos testes.
- Mockito: Para criação de mocks e simulação de dependências.
- AssertJ e Hamcrest: Para realizar asserções fluentes e legíveis.
- JsonPath: Para validação de respostas JSON.
- Jacoco: Para gerar relatórios de cobertura de testes.
- Pitest: Para realizar testes mutantes e garantir a eficácia dos testes unitários.
A interface PlanetRepository é responsável pela interação com o banco de dados para a entidade Planet.
Ela estende CrudRepository e QueryByExampleExecutor do Spring Data JPA, fornecendo métodos para operações básicas de
CRUD e consultas personalizadas baseadas em exemplos.
-
Optional<Planet> findByName(String name): Busca um planeta pelo nome. Retorna umOptionalcontendo o planeta encontrado ou vazio, caso não exista. -
<S extends Planet> List<S> findAll(Example<S> example): Sobrescreve o métodofindAllpara permitir a busca de todos os planetas que correspondem ao exemplo fornecido.
-
CrudRepository<Planet, Long>: Fornece métodos para operações CRUD (Create, Read, Update, Delete) básicos.
save(S entity): Salva uma entidadePlanet.findById(ID id): Busca um planeta pelo seu ID.deleteById(ID id): Remove um planeta pelo seu ID.findAll(): Retorna todos os planetas.
-
QueryByExampleExecutor: Permite consultas dinâmicas baseadas em exemplos. Um exemplo é um objeto parcialmente preenchido, onde os campos preenchidos servem como critérios para a consulta.
@Repository: (implicitamente adicionada pelo Spring Data JPA) Marca a interface como um repositório Spring Data, que será gerenciado pelo container Spring.
A interface PlanetRepository pode ser testada utilizando:
- Spring Boot Test: Para testar a integração com o contexto de persistência.
- JUnit 5: Para criação e execução dos testes.
- Mockito: Para simulação de repositórios durante os testes.
- AssertJ e Hamcrest: Para realizar asserções fluentes e legíveis.
- Jacoco: Para gerar relatórios de cobertura de testes.
- Pitest: Para garantir a eficácia dos testes de repositório.
A classe PlanetService é responsável por fornecer a lógica de negócios relacionada aos planetas na aplicação.
Ela utiliza o repositório PlanetRepository para realizar operações de criação, busca, listagem e remoção de planetas.
planetRepository(PlanetRepository): Dependência injetada usada para interagir com o banco de dados.
- PlanetService(PlanetRepository planetRepository): Construtor que injeta o repositório de planetas, necessário para realizar as operações de CRUD.
-
Planet create(Planet planet): Cria e salva um novo planeta no banco de dados. -
Optional<Planet> get(Long id): Busca um planeta pelo seu ID. Retorna umOptionalcontendo o planeta encontrado ou vazio, caso não exista. -
Optional<Planet> getByName(String name): Busca um planeta pelo seu nome. Retorna umOptionalcontendo o planeta encontrado ou vazio, caso não exista. -
List<Planet> list(String terrain, String climate): Lista todos os planetas que correspondem ao terreno e clima especificados. Utiliza a funcionalidade de consulta por exemplo (Query by Example) para construir a consulta. -
void remove(Long id): Remove um planeta do banco de dados pelo seu ID.
@Service: Indica que a classe é um componente de serviço do Spring, que contém a lógica de negócios e pode ser injetado em outros componentes.
A classe PlanetService pode ser testada utilizando:
- Spring Boot Test: Para testar a integração com o contexto da aplicação.
- JUnit 5: Para criação e execução dos testes.
- Mockito: Para simular o comportamento do repositório durante os testes de unidade.
- AssertJ e Hamcrest: Para realizar asserções fluentes e legíveis.
- Jacoco: Para gerar relatórios de cobertura de testes.
- Pitest: Para garantir a eficácia dos testes unitários, especialmente para a lógica de negócios.
A classe QueryBuilder é uma classe utilitária que fornece um método para criar consultas dinâmicas utilizando o
mecanismo de Query by Example do Spring Data JPA. Ela é usada para construir consultas baseadas em exemplos de entidades Planet, permitindo a busca de planetas no banco de dados com base em critérios parciais.
static Example<Planet> makeQuery(Planet planet): Este método cria uma instância deExample<Planet>usando o objetoplanetfornecido. Ele utiliza umExampleMatcherque configura a consulta para:- matchingAll(): Correspondência de todos os campos preenchidos.
- withIgnoreCase(): Ignorar a sensibilidade a maiúsculas e minúsculas.
- withIgnoreNullValues(): Ignorar campos nulos na entidade
planetao criar a consulta.
- Classe utilitária:
QueryBuilderé uma classe utilitária, ou seja, ela não deve ser instanciada. Para garantir isso, o construtor padrão é privado.
A classe QueryBuilder é tipicamente utilizada em serviços que precisam construir consultas dinâmicas baseadas em
atributos de um planeta. Por exemplo, na classe PlanetService, o método list utiliza QueryBuilder.makeQuery()
para construir a consulta que será passada ao repositório.
Planet planet = new Planet("desert", "arid");
Example<Planet> query = QueryBuilder.makeQuery(planet);
List<Planet> results = planetRepository.findAll(query);A classe QueryBuilder pode ser testada utilizando:
- JUnit 5: Para verificar a correta construção das consultas.
- AssertJ e Hamcrest: Para asserções fluentes e legíveis sobre os exemplos criados.
- Como a classe
QueryBuilderé utilitária e possui apenas métodos estáticos, não é necessário instanciá-la. O design da classe segue o princípio de ocultar o construtor para impedir sua instância. - O
ExampleMatcherconfigurado garante que as consultas sejam flexíveis, ignorando a capitalização e valores nulos, o que facilita a busca de planetas com base em diferentes critérios.
Pergunta: O que são os testes mutantes?
Resposta: A ideia é criar mutações no código, para avaliar e verificar se o código quebra. Se o código for alterado e o teste não quebrar, então ele está errado, pois o teste deve sim quebrar.
Para avaliar isso, podemos usar o teste mutante. Com ele podemos realizar uma execução e verificar se o teste detecta essa mutação, ou seja, se quando eu mudo o código, o teste quebra e se ele realmente está “testando” algo.
É um teste mais lento e não deve rodar junto ao teste de integração, pois o teste mutante usa a dependência do Pitest, que deve ser configurado no pom.xml especificando versão, apontando os parâmetros e classes.
O projeto requer um banco de dados MySQL, então é necessário criar uma base de dados com os seguintes comandos:
$ sudo mysql
CREATE USER 'user'@'%' IDENTIFIED BY '123456';
GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' WITH GRANT OPTION;
exit
$ mysql -u user -p
CREATE DATABASE starwars;
exitDurante os testes, as tabelas de banco já serão criadas automaticamente no banco de dados.
1 - Para construir e testar, execute o comando:
$ ./mvnw clean verify2 - Para executar o Teste Mutante, foi necessário executar o comando abaixo:
C:\Star-Wars-Planets-API\Testes\sw-planet-api> ./mvnw test-compile org.pitest:pitest-maven:mutationCoverage
