O Maven é a ferramenta de construção mais popular no espaço Java, enquanto o teste de integração é uma parte essencial do processo de desenvolvimento. Portanto,it’s a natural choice to configure and execute integration tests with Maven.
Neste tutorial, examinaremos várias maneiras diferentes de usar o Maven para testes de integração e separar os testes de integração dos testes de unidade.
2. Preparação
Para tornar o código de demonstração próximo a um projeto do mundo real, vamos configurar um aplicativo JAX-RS. Este aplicativo é implantado em um servidor antes da execução dos testes de integração e desmontado posteriormente.
2.1. Configuração do Maven
Vamos construir nosso aplicativo REST em Jersey - a implementação de referência do JAX-RS. Esta implementação requer algumas dependências:
Podemos encontrar as versões mais recentes dessas dependênciashereehere.
Usaremos o plugin Jetty Maven para configurar um ambiente de teste. This plugin starts a Jetty server during the pre-integration-test phase of the Maven build lifecycle, then stops it in the post-integration-test phase.
Veja como configuramos o plugin Jetty Maven empom.xml:
Quando o servidor Jetty for inicializado, ele estará escutando na porta8999. Os elementos de configuraçãostopKeyestopPort são usados exclusivamente pela metastop do plug-in e seu valor não é importante de nossa perspectiva.
Here é onde encontrar a última versão do plugin Jetty Maven.
Outra coisa a notar é que devemos definir o elementopackaging no arquivopom.xml parawar, caso contrário, o plugin Jetty não pode iniciar o servidor:
war
2.2. Criação de um aplicativo REST
O ponto de extremidade do aplicativo é muito simples - retornando uma mensagem de boas-vindas quando uma solicitação GET atinge a raiz de contexto:
@Path("/")
public class RestEndpoint {
@GET
public String hello() {
return "Welcome to example!";
}
}
É assim que registramos a classe de terminal com Jersey:
package com.example.maven.it;
import org.glassfish.jersey.server.ResourceConfig;
public class EndpointConfig extends ResourceConfig {
public EndpointConfig() {
register(RestEndpoint.class);
}
}
Para que o servidor Jetty reconheça nosso aplicativo REST, podemos usar um descritor de implantação clássicoweb.xml:
This descriptor must be placed in the directory /src/main/webapp/WEB-INF a ser reconhecido pelo servidor.
2.3. Código de teste do lado do cliente
Todas as classes de teste nas seções a seguir contêm um único método:
@Test
public void whenSendingGet_thenMessageIsReturned() throws IOException {
String url = "http://localhost:8999";
URLConnection connection = new URL(url).openConnection();
try (InputStream response = connection.getInputStream();
Scanner scanner = new Scanner(response)) {
String responseBody = scanner.nextLine();
assertEquals("Welcome to example!", responseBody);
}
}
Como podemos ver, esse método não faz nada além de enviar uma solicitação GET para o aplicativo da Web que configuramos anteriormente e verificar a resposta.
3. Teste de integração em ação
Uma coisa importante a notar sobre o teste de integração é quetest methods often take quite a long time to run.
Como resultado, devemos excluir os testes de integração do ciclo de vida da construção padrão, impedindo-os de desacelerar todo o processo toda vez que construímos um projeto.
A convenient way to separate integration tests is to use build profiles. Este tipo de configuração nos permite executar testes de integração apenas quando necessário - especificando um perfil adequado.
Nas seções a seguir, configuraremos todos os testes de integração com perfis de construção.
Por padrão, o plugin Mavensurefire executa testes de unidade durante a fasetest, enquantothe failsafe plugin runs integration tests in the integration-test phase.
Podemos nomear classes de teste com padrões diferentes para esses plugins para coletar os testes em anexo separadamente.
As convenções de nomenclatura padrão aplicadas porsurefireefailsafe são diferentes, portanto, só precisamos seguir essas convenções para separar os testes de unidade e integração.
A execução do pluginsurefire inclui todas as classes cujo nome começa comTest, ou termina comTest,Tests ouTestCase. Em contraste, o pluginfailsafe executa métodos de teste em classes cujo nome começa comIT, ou termina comIT ouITCase.
This é onde podemos encontrar a documentação sobre a inclusão de teste parasurefire, ehere é parafailsafe.
Vamos adicionar o pluginfailsafe ao POM com a configuração padrão:
Além do pluginfailsafe,we can also use the surefire plugin to execute unit and integration tests in different phases.
Vamos supor que queremos nomear todos os testes de integração com o sufixoIntegrationTest. Como o plug-insurefire executa testes com esse nome na fasetest por padrão, precisamos excluí-los da execução padrão:
Tiramos todas as classes de teste com um nome terminando comIntegrationTest fora do ciclo de vida de construção. É hora de colocá-los de volta com um perfil:
Instead of binding the test goal of the surefire plugin to the test build phase, as usual, we bound it to the integration-test phase. O plugin será iniciado durante o processo de teste de integração.
Observe que devemos definir um elementoexclude paranone para substituir a exclusão especificada na configuração básica.
Agora, vamos definir uma classe de teste de integração com nosso padrão de nomenclatura:
public class RestIntegrationTest {
// test method shown in subsection 2.3
}
Este teste estará sendo executado com o comando:
mvn verify -Psurefire
6. Testando com o Cargo Plugin
Podemos usar o pluginsurefire com o plugin Mavencargo. Este plug-in vem com suporte interno para servidores incorporados, que são muito úteis para testes de integração.
Mais detalhes sobre esta combinação podem ser encontradoshere.
7. Testando com@Category da JUnit
Uma maneira conveniente de executar testes seletivamente é aproveitarthe @Category annotation na estrutura JUnit 4. This annotation lets us exclude particular tests from unit testing, and include them in integration testing.
Primeiro, precisamos de uma interface ou classe para funcionar como um identificador de categoria:
package com.example.maven.it;
public interface Integration { }
Podemos então decorar uma classe de teste com a anotação@Category e o identificadorIntegration:
@Category(Integration.class)
public class RestJUnitTest {
// test method shown in subsection 2.3
}
Em vez de declarar a anotação@Category em uma classe de teste, também podemos usá-la no nível do método para categorizar métodos de teste individuais.
Excluir uma categoria da fase de construçãotest é simples:
Agora podemos executar testes de integração com um comando Maven:
mvn verify -Pcategory
8. Adicionando um diretório separado para testes de integração
É desejável às vezes ter um diretório separado para testes de integração. Organizing tests this way allows us to entirely isolate integration tests from unit tests.
Podemos usar o plugin Mavenbuild helper para este propósito:
Here é onde podemos encontrar a versão mais recente deste plugin.
A configuração que acabamos de ver adiciona um diretório de origem de teste ao build. Vamos adicionar uma definição de classe a esse novo diretório:
public class RestITCase {
// test method shown in subsection 2.3
}
É hora de executar testes de integração nesta aula:
mvn verify -Pfailsafe
O plugin Mavenfailsafe executará métodos nesta classe de teste devido à configuração que definimos na subseção 3.1.
Um diretório de origem de teste geralmente acompanha um diretório de recursos. Podemos adicionar esse diretório em outro elementoexecution para a configuração do plugin:
Este artigo abordou o uso do Maven para executar testes de integração com um servidor Jetty, focando na configuração dos plug-inssurefireefailsafe do Maven.
O código-fonte completo para este tutorial pode ser encontradoover on GitHub.