Configurando testes de mutação utilizando Stackspot🧠
Tags: testing, mutationtest, stackspot, qa
Published: 2023-04-12 22:31:32

<meta name="google-site-verification" content="8GYh5toC89sN7cOqlXEdAh1o3OBBIAFD4axNspbRcx4" />


Recentemente, analisamos como a ferramenta Stackspot pode acelerar o processo de automação de testes em um artigo intitulado [acelerando o processo de automação de testes utilizando stackspot](https://dev.to/marlo2222/acelerando-o-processo-de-automacao-de-testes-utilizando-stackspot-3oap), onde demonstramos como criar um novo projeto de forma rápida e fácil. Agora a questão é como adicionar configurações de testes usando a Stackspot a um projeto já existente.

Nesse artigo, veremos como podemos realizar a configuração de testes de mutação em um projeto backend já existente utilizando um plugin criado com Stackspot.

## O que são testes de mutação?👥

O Teste de Mutação é uma técnica de teste de software que consiste em alterar partes específicas do código-fonte para verificar se os testes elaborados conseguem identificar os erros resultantes das mudanças. 

O objetivo é avaliar a qualidade dos testes e sua capacidade de detectar falhas no código-fonte que foi modificado, por isso as mudanças ou também chamados de mutantes são pequenas para não afetar o objetivo geral do programa. 

Essa técnica é também conhecida como estratégia de teste baseada em falhas e é principalmente usada para verificar a qualidade dos  testes de unidade que foram desenvolvidos.

### Etapas para execução📑

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mqhmblrcstdycue2ux38.png)

O processo de Teste de Mutação envolve alguns passos, entre eles: 
  
- Primeiro, falhas são introduzidas no código-fonte, criando mutantes que devem falhar na execução dos testes. 
- Em seguida, os casos de teste são aplicados tanto ao programa original quanto aos mutantes. Se os resultados dos programas original e mutante forem diferentes, o mutante é eliminado pelo caso de teste, demonstrando sua eficácia. 
- Se os resultados forem os mesmos, o mutante é mantido ativo, e teste mais eficazes precisam ser criados para detectar a mudança entre o programa original e o mutante. 

O objetivo final é garantir a qualidade dos casos de teste e a robustez do software a mudanças.

### Mudanças em um programa mutante📐

Existem diversas técnicas utilizadas para gerar mutantes, sendo as mais comuns:

- Operadores de substituição de operando: substituem um operando por outro ou por um valor constante.
- Operadores de modificação de expressão: alteram a expressão original, inserindo ou substituindo operadores.
- Operadores de modificação de instrução: alteram a instrução original, inserindo ou removendo instruções.

Essas técnicas podem ser combinadas para gerar mutantes com diferentes tipos de falhas, aumentando a eficácia do Teste de Mutação. 

Para obter mais informações sobre as diferentes abordagens de geração de mutantes, você pode consultar a documentação da ferramenta pitest, que está disponível no seguinte [link](https://pitest.org/quickstart/mutators/).

### Ferramentas🔨
Existem várias ferramentas disponíveis para realizar testes de mutação em projetos Java/Kotlin. Uma das ferramentas mais conhecidas é o Pitest, que será utilizada neste artigo.

## Mão na massa👩‍💻

### Pré-requisito📑
- Java JDK.
- [Stackspot CLI](https://docs.stackspot.com/en/docs/stk-cli/installation/).

### Projeto de exemplo📚
Neste artigo, utilizaremos o projeto pequeno investidor, uma aplicação pessoal que disponibiliza informações do mercado financeiro por meio de uma API que extrai as informações utilizando web scraping.

O projeto está estruturado em Java e utiliza o gerenciador de dependências Maven. A estrutura do projeto é a seguinte:

```
├───src
│   ├───main
│   │   ├───java
│   │   │   └───com
│   │   │       └───money
│   │   │           └───pequenoinvestidor
│   │   │               ├───configuration
│   │   │               ├───controller
│   │   │               ├───model
│   │   │               ├───services
│   │   │               │   └───imp
│   │   │               └───util
│   │   └───resources
│   └───test
│       └───java
│           └───com
│               └───money
│                   └───pequenoinvestidor
│                       └───integração
```

###Importando nossa stack🧐

Utilizaremos a stack [qa-api-stack](https://github.com/marlo2222/qa-api-stack), que tem como objetivo acelerar a criação de testes de API.

Como vimos anteriormente, os plugins permitem adicionar novas capacidades à sua aplicação. Neste caso, utilizaremos um plugin da stack qa-api-stack que realiza as configurações necessárias para a realização de testes de mutação em seu projeto.

Para instalar a stack, basta utilizar o seguinte comando:

```
stk import stack https://github.com/marlo2222/qa-api-stack
```

Após a instalação da stack pela CLI, é possível verificar as stacks disponíveis usando o comando `stk list stack`.

```
+------------------+--------+-----------------------------------------------------------+
| name             | type   | description                                               |
+------------------+--------+-----------------------------------------------------------+
| qa-api-stack     | remote | Stack para automaçãoes de API utilizando rest assured.    |
|                  |        |                                                           |
| qa-cypress-stack | remote | stack para a criação de projetos de automação com cypress |
+------------------+--------+-----------------------------------------------------------+
```

É importante ressaltar que a partir de agora, podemos obter uma lista dos plugins disponíveis nas stacks instaladas usando o comando `stk list plugin`.


```
+-------------+-----------------------------------------------------+-----------------+
| name        | description                                         | version(latest) |
+-------------+-----------------------------------------------------+-----------------+
| pitest-java | Plugin para a configuração de testes de mutação com | Sem release     |
|             | a ferramenta pitest em projetos java.               |                 |
+-------------+-----------------------------------------------------+-----------------+
```

> **Importante:** Essa é uma stack para fins didáticos e que seu principal objetivo, que é a configuração de testes de API, ainda está em desenvolvimento.

### Utilizando o plugin🔌

Para utilizar o plugin `pitest-java`, é necessário estar dentro do diretório da aplicação desejada. Neste exemplo, a aplicação é o `pequenoinvestidor.`

```
cd pequenoinvestidor
```
Na raiz do projeto, utilize o seguinte comando para aplicar o plugin de configuração de testes de mutação ao projeto: 

```
stk apply plugin -s qa-api-stack/pitest-java
```

> Um destaque ao argumento -s, ele basicamente ignora a checagem de aplicativos que não foram criados utilizando Stackspot, como é o exemplo do projeto pequeno investidor.

Será necessários fornecer algumas entradas para a configuração do plugin. A primeira delas é referente ao gerenciador de dependências utilizado no projeto. O plugin da suporte a projetos `maven` e `gradle` utilizando groovy. Nesse exemplo utilizaremos maven.

```
? Qual gerenciador de dependenciais do projeto?
 » 1) Maven
   2) Gradle
  Answer: 1) Maven
```
A próxima informação que você precisa fornecer é referente à biblioteca de logs utilizada no projeto. No projeto pequeno investidor, está sendo utilizada a biblioteca `org.slf4j.Logger`.

```
? Qual lib de logs utilizada no projeto? (Use shortcuts or arrow keys)
   1) java.util.logging
   2) org.apache.log4j
 » 3) org.slf4j
   4) org.apache.commons.logging
  Answer: 3) org.slf4j

```

> Trechos de logs podem interferir nos resultados do teste de mutação, precisamos informar para a ferramenta pitest para ignora trechos de log por meio da configuração avoidCallsTo.

Em seguida, você precisará informar qual é a cobertura de mutantes esperada para o projeto após a execução dos testes de mutação. Como o projeto pequeno investidor possui pouca cobertura de testes unitários, vamos informar o valor de 50%.

```
 Qual cobertura de mutantes esperada?(1% a 99%) 
```
> A cobertura de mutantes é definida como a porcentagem de mutantes mortos pelo número total de mutantes gerados: (Mutantes Mortos / Número Total de Mutantes) * 100. É um excelente indicador para avaliar se os testes unitários estão conseguindo identificar os mutantes. Taxas elevadas de mutantes sobreviventes resultam em baixa cobertura de mutantes.

A seguir você precisara informar qual o grupo de mutantes será configurado no seu projeto. Essa é uma informação que diz respeito a quantidade de variações/tipos de mutantes que serão gerados. Por padrão a ferramenta pitest considera os mutantes OLD_DEFAULTS, no entanto vamos selecionar a opção DEFAULTS:

```
? Grupo de mutantes a ser utilizado?
   1) OLD_DEFAULTS
 » 2) DEFAULTS
   3) STRONGER
   4) ALL
  Answer: 2) DEFAULTS
```

> Mais detalhes sobre as mutações geradas no código da aplicação com base no grupo escolhido podem ser conferidas em [mutators ](https://pitest.org/quickstart/mutators/).

Chegamos a duas informações extremamente importantes. Primeiramente, precisamos informar ao Pitest o pacote onde se localizam as classes da nossa aplicação para que a ferramenta possa gerar os mutantes. Embora pudessemos simplesmente informar `com.*` para que a ferramenta gere mutantes para todas as classes do projeto, isso não é uma prática recomendada. Neste exemplo, informarei o seguinte pacote `com.money.pequenoinvestidor.services.imp.CalculoServiceImp`

```
? Qual o pacote das classes a serem gerados mutantes?com.money.pequenoinvestidor.services.imp.CalculoServiceImp
```

> Nos testes de mutação, é importante estarmos atentos as classes em que as mutações no código serão aplicadas. O objetivo é avaliar se mudanças nas regras de negócio são identificadas pelos nossos testes unitários. Dependendo da arquitetura do projeto, é recomendado concentrarmos nas classes que implementam essas regras de negócio, ignorando interfaces, classes abstratas ou outros pontos do código que podem interferir no resultado dos testes de mutação.

precisamos informar o pacote onde estão localizadas as classes de testes do nosso projeto. Neste exemplo, utilizaremos o pacote de testes `com.money.pequenoinvestidor.TestCalculoServiceImp `

```
? Qual o pacote dos testes unitários? com.money.pequenoinvestidor.TestCalculoServiceImp
```
Ao final do processo, a Stackspot informará que o plugin foi aplicado com sucesso ao projeto:

```
- Plugin qa-api-stack/pitest-java aplicado.
```
Acessando o arquivo `pom.xml` do projeto pequeno investido, podemos observar que as configurações para o plugin do pitest foram aplicadas, e as entradas que fornecemos serviram como base para essa configuração: 

```
<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
            	<groupId>org.apache.maven.plugins</groupId>
            	<artifactId>maven-surefire-plugin</artifactId>
            	<version>3.0.0-M7</version>
				<configuration>
          			<excludes>
            			<exclude>**/FiisTest.java</exclude>
          			</excludes>
        		</configuration>
            	<dependencies>
                	<dependency>
                   		<groupId>org.junit.jupiter</groupId>
                    	<artifactId>junit-jupiter-engine</artifactId>
                    	<version>5.4.0</version>
                	</dependency>
           		</dependencies>
        	</plugin>
			<plugin>
				<groupId>org.pitest</groupId>
				<artifactId>pitest-maven</artifactId>
				<version>1.5.0</version>
				<configuration>
					<targetClasses>
						<param>com.money.pequenoinvestidor.services.imp.CalculoServiceImp</param>
					</targetClasses>
					<targetTests>
						<param>com.money.pequenoinvestidor.TestCalculoServiceImp</param>
					</targetTests>
					<mutators>
						<mutator>DEFAULTS</mutator>
					</mutators>
					<outputFormats>
						<outputFormat>HTML</outputFormat>
						<outputFormat>XML</outputFormat>
					</outputFormats>
					<failWhenNoMutations>false</failWhenNoMutations>
					<avoidCallsTo>
						<avoidCallsTo>org.slf4j</avoidCallsTo>
					</avoidCallsTo>
					<mutationThreshold>50</mutationThreshold>
				</configuration>
			</plugin>
		</plugins>
```

### Executando os teste de mutação😁
Uma vez que a ferramenta Pitest foi configurada em nosso projeto, podemos executar os testes de mutação com facilidade. Para isso, basta utilizar o seguinte comando com o Maven:

```
mvn test-compile org.pitest:pitest-maven:mutationCoverage
```

Teremos uma saída semelhante a esta:

```
--------------------------------------------------------------------------------
> Total  : 1 seconds
--------------------------------------------------------------------------------
================================================================================
- Statistics
================================================================================
>> Generated 14 mutations Killed 11 (79%)
>> Ran 19 tests (1.36 tests per mutation)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.977 s
[INFO] Finished at: 2023-04-12T18:28:29-03:00
[INFO] ------------------------------------------------------------------------
```

> Podemos observar que apensar de um limite de cobertura de **50%** definido, os resultados para a classe CalculoServiceImp foram interessantes, de 14 mutações geradas no código **79%** foram identificadas por testes unitários existentes.😅

O pitest já gera relatórios de saída, e por meio deles podemos identificar alguns pontos como dados de cobertura:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yg19w4i3skve573d1w8c.png)

Os tipos de mutantes que foram gerados com base no grupo escolhido, e alguns detalhes da mutação:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gehwcm5n7t2y65fqtgpp.png)

##Conclusão💖

Muito além de escrever testes unitários, precisamos nos preocupar com a qualidade dos testes que são escritos. É aí que entra o teste de mutação, uma técnica poderosa que pode nos ajudar a identificar falhas na lógica do código. 

Aqui podemos observar mais um exemplo pratico em que a Stackspot pode ser utilizada para nos auxiliar na parte de testes e qualidade de software. Ressaltando mais um vez o quão simples você pode tornar a configuração de testes de mutação utilizando a ferramenta.✨

E como sugestão, gostaria que vocês tente a configuração em um projeto `gradle`.😎

Sinta-se à vontade para qualquer dúvida!😀

📩 [linkedin](https://www.linkedin.com/in/marlo-henrique-84a940109/)
🐱‍👤 [github](https://github.com/marlo2222)

> Quer sabe mais sobre stackspot? vou esta deixando o link para o github oficial onde você pode encontrar os principais contatos para o [time da stackspot](https://github.com/stack-spot).✨