Executando Especificações de Integração do Kotest com Maven

Depois de concluirmos esta aula, nós:

  • Saberemos como configurar os diretórios de código-fonte (src/integration-test/kotlin) e recursos (src/integration-test/resources) para especificações de integração no Maven.
  • Compreenderemos como pular testes unitários ou testes de integração utilizando perfis do Maven (dev vs integration-test).
  • Saberemos como executar especificações de integração do Kotest 6 usando o Maven Failsafe Plugin.

1. Os Requisitos do Nosso Build Maven

Os requisitos do nosso build Maven são:

  • Nossos testes de integração devem ter um diretório de código-fonte separado: src/integration-test/kotlin.
  • Nossos testes de integração devem ter um diretório de recursos separado: src/integration-test/resources.
  • Apenas os testes unitários devem ser executados por padrão.
  • Devemos ser capazes de executar apenas os testes de integração sob demanda.

Vamos começar criando os perfis do Maven responsáveis por alternar entre a execução dos testes unitários e dos testes de integração.


2. Criando os Perfis do Maven Necessários

Precisamos criar dois perfis no nosso pom.xml:

  • O perfil dev é o perfil padrão do nosso build e garante que apenas os testes unitários sejam executados quando ele estiver ativo.
  • O perfil integration-test garante que apenas os testes de integração sejam executados quando for ativado.

Podemos criar esses perfis em dois passos:

Primeiro, adicionamos duas propriedades na seção <properties> do pom.xml:

  • skip.unit.tests: true quando o Maven deve pular os testes unitários (false por padrão).
  • skip.integration.tests: true quando o Maven deve pular os testes de integração (true por padrão).
1
2
3
4
<properties>
    <skip.unit.tests>false</skip.unit.tests>
    <skip.integration.tests>true</skip.integration.tests>
</properties>

Segundo, declaramos os perfis dev (ativo por padrão) e integration-test na seção <profiles>:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<profiles>
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>
    <profile>
        <id>integration-test</id>
        <properties>
            <skip.integration.tests>false</skip.integration.tests>
            <skip.unit.tests>true</skip.unit.tests>
        </properties>
    </profile>
</profiles>

A seguir, vamos configurar os diretórios de código-fonte dos nossos testes unitários e de integração.


3. Configurando os Diretórios de Código-Fonte (kotlin-maven-plugin)

Como escrevemos tanto nossos testes unitários quanto nossas especificações de integração em Kotlin, o compilador kotlin-maven-plugin precisa conhecer ambos os diretórios (src/test/kotlin e src/integration-test/kotlin).

Configuramos a seção <sourceDirs> da execução test-compile do kotlin-maven-plugin (ou adicionamos ambos os diretórios via build-helper-maven-plugin) da seguinte maneira:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<plugin>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-maven-plugin</artifactId>
    <version>2.4.21</version>
    <executions>
        <execution>
            <id>compile</id>
            <goals>
                <goal>compile</goal>
            </goals>
        </execution>
        <execution>
            <id>test-compile</id>
            <goals>
                <goal>test-compile</goal>
            </goals>
            <configuration>
                <sourceDirs>
                    <sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
                    <sourceDir>${project.basedir}/src/integration-test/kotlin</sourceDir>
                </sourceDirs>
            </configuration>
        </execution>
    </executions>
</plugin>

4. Configurando o Diretório de Recursos dos Testes de Integração

Para adicionar o diretório de recursos src/integration-test/resources ao classpath de teste do Maven, utilizamos o Build Helper Maven Plugin (build-helper-maven-plugin):

Primeiro, declaramos o plugin na seção <plugins> do pom.xml:

1
2
3
4
5
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <version>3.6.0</version>
</plugin>

Segundo, configuramos uma execução que invoca o goal add-test-resource na fase generate-test-resources adicionando o diretório src/integration-test/resources:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <version>3.6.0</version>
    <executions>
        <execution>
            <id>add-integration-test-resources</id>
            <phase>generate-test-resources</phase>
            <goals>
                <goal>add-test-resource</goal>
            </goals>
            <configuration>
                <resources>
                    <resource>
                        <directory>src/integration-test/resources</directory>
                        <filtering>true</filtering>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>

5. Configurando o Maven Surefire para Pular Testes Unitários Quando Solicitado

O Maven Surefire Plugin não executa os testes unitários quando sua propriedade <skipTests> é true. Vinculamos <skipTests> à nossa propriedade ${skip.unit.tests}:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.5.2</version>
    <configuration>
        <includes>
            <include>**/*Spec.java</include>
        </includes>
        <systemPropertyVariables>
            <kotest.tags>UnitTest</kotest.tags>
        </systemPropertyVariables>
        <skipTests>${skip.unit.tests}</skipTests>
    </configuration>
</plugin>

Antes de configurarmos o Maven Failsafe Plugin, vamos escrever uma especificação simples de integração.


6. Escrevendo uma Especificação Simples de Integração

A classe GetMessageSpec (localizada em src/integration-test/kotlin) contém uma especificação que verifica se o método getMessage() de MessageService retorna "Hello World!". Marcamos essa classe com a tag IntegrationTest:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package com.testwithspring.master

import io.kotest.core.annotation.Tags
import io.kotest.core.spec.style.ShouldSpec
import io.kotest.matchers.shouldBe

@Tags("IntegrationTest")
class GetMessageSpec : ShouldSpec({

    val messageService = MessageService()

    should("Get message") {
        messageService.getMessage() shouldBe "Hello World!"
    }
})

Onde IntegrationTest é nosso objeto marcador de tag:

1
2
3
4
5
package com.testwithspring.master

import io.kotest.core.Tag

object IntegrationTest : Tag()

7. Executando Testes de Integração com o Maven Failsafe Plugin

Utilizamos o Maven Failsafe Plugin (maven-failsafe-plugin) para executar nossos testes de integração construindo a configuração em quatro passos:

  1. Garantimos que ambos os goals integration-test (que executa os testes) e verify (que falha o build caso algum teste de integração tenha falhado) sejam invocados.
  2. Configuramos <includes> para incluir todas as classes terminadas com **/*Spec.java.
  3. Passamos <kotest.tags>IntegrationTest</kotest.tags> em <systemPropertyVariables> para que apenas as especificações de integração sejam executadas.
  4. Vinculamos <skipTests> à propriedade ${skip.integration.tests} para que os testes de integração só rodem quando o perfil integration-test estiver ativo:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>3.5.2</version>
    <executions>
        <execution>
            <id>integration-tests</id>
            <goals>
                <goal>integration-test</goal>
                <goal>verify</goal>
            </goals>
            <configuration>
                <includes>
                    <include>**/*Spec.java</include>
                </includes>
                <systemPropertyVariables>
                    <kotest.tags>IntegrationTest</kotest.tags>
                </systemPropertyVariables>
                <skipTests>${skip.integration.tests}</skipTests>
            </configuration>
        </execution>
    </executions>
</plugin>

8. Executando Nossos Testes Unitários e de Integração

Para executar apenas os testes unitários, rodamos:

1
mvn clean test -P dev

Saída no terminal:

1
2
3
4
5
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.testwithspring.master.MessageServiceSpec
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.089 s -- in com.testwithspring.master.MessageServiceSpec

Para executar apenas os testes de integração, rodamos:

1
mvn clean verify -P integration-test

Saída no terminal:

1
2
3
4
5
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.testwithspring.master.GetMessageSpec
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.091 s -- in com.testwithspring.master.GetMessageSpec

Resumo

Nesta aula, aprendemos quatro pontos essenciais:

  • Configuramos o kotlin-maven-plugin para compilar tanto src/test/kotlin quanto src/integration-test/kotlin.
  • Adicionamos src/integration-test/resources usando o build-helper-maven-plugin.
  • Executamos nossas especificações de integração do Kotest usando o maven-failsafe-plugin filtrado por kotest.tags=IntegrationTest.
  • Controlamos a ativação das suítes unitária e de integração por meio dos perfis Maven dev e integration-test.