Junit: teste de integração de divisão e testes de unidade

126

Eu herdei uma carga de teste Junit, mas esses testes (além da maioria não está funcionando) são uma mistura de testes de unidade e testes de integração reais (exigindo sistemas externos, banco de dados, etc.).

Então, eu estou tentando pensar em uma maneira de separá-los, para que eu possa executar o teste de unidade de maneira agradável e rápida e os testes de integração depois disso.

As opções são ..

  1. Divida-os em diretórios separados.

  2. Vá para Junit4 (da v3) e anote as classes para separá-las.

  3. Use uma convenção de nomenclatura de arquivos para informar o que é uma classe, ou seja, AdapterATest e AdapterAIntergrationTest.

3 tem o problema de que o Eclipse tem a opção de "Executar todos os testes no projeto / pacote ou pasta selecionado". Portanto, seria muito difícil apenas executar os testes de integração.

2: corre o risco de que os desenvolvedores possam começar a escrever testes de integração em classes de teste de unidade e isso fica confuso.

1: Parece a melhor solução, mas meu intestino diz que deve haver uma solução melhor por aí.

Portanto, essa é minha pergunta: como você divide os testes de integração e os testes de unidade adequados?

jeff porter
fonte
Gostaria apenas de agradecer a todos pela contribuição, sei que essa é uma pergunta subjetiva e não tem uma resposta correta. Mas você me ajudou a perceber que não há outras opções além das listadas. Acho que vou seguir com a estrutura de diretórios no momento e mudar para JUnit4, embora não use anotações para dividi-las ainda.
Jeff Porter

Respostas:

10

Atualmente, uso diretórios separados devido à política organizacional (e ao legado do Junit 3), mas estou procurando fazer a transição para anotações agora que estou no Junit 4.

Eu não estaria muito preocupado com os desenvolvedores colocando testes de integração em suas classes de teste de unidade - adicione uma regra nos seus padrões de codificação, se necessário.

Estou interessado em saber que tipo de outras soluções podem existir além de anotações ou separar fisicamente as classes.

Steven Mackenzie
fonte
145

Você pode dividi-los facilmente usando as categorias JUnit e Maven.

Isso é mostrado muito, muito brevemente abaixo, dividindo os testes de unidade e integração.

Definir uma interface de marcador

A primeira etapa no agrupamento de um teste usando categorias é criar uma interface de marcador.

Essa interface será usada para marcar todos os testes que você deseja executar como testes de integração.

public interface IntegrationTest {}

Marque suas aulas de teste

Adicione a anotação da categoria ao topo da sua classe de teste. Leva o nome da sua nova interface.

import org.junit.experimental.categories.Category;
@Category(IntegrationTest.class)
public class ExampleIntegrationTest{
  @Test
  public void longRunningServiceTest() throws Exception {
  }
}

Configurar testes de unidade Maven

A beleza desta solução é que nada realmente muda para o lado do teste de unidade.

Simplesmente adicionamos alguma configuração ao plug-in maven surefire para que ele ignore todos os testes de integração.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <includes>
      <include>**/*.class</include>
    </includes>
    <excludedGroups>com.test.annotation.type.IntegrationTest</excludedGroups>
  </configuration>
</plugin>

Quando você faz um teste de limpeza mvn, apenas os testes de unidade não marcados serão executados.

Configurar testes de integração do Maven

Novamente, a configuração para isso é muito simples.

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

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <groups>com.test.annotation.type.IntegrationTest</groups>
  </configuration>
</plugin>

Se você agrupar isso em um perfil com id IT, poderá executar apenas os testes rápidos usando mvn clean install. Para executar apenas os testes de integração / lentos, use mvn clean install -P IT.

Mas na maioria das vezes, você desejará executar os testes rápidos por padrão e todos os testes com -P IT. Se for esse o caso, você precisará usar um truque:

<profiles>
    <profile>
        <id>IT</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <excludedGroups>java.io.Serializable</excludedGroups> <!-- An empty element doesn't overwrite, so I'm using an interface here which no one will ever use -->
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

Como você pode ver, estou excluindo os testes anotados java.io.Serializable. Isso é necessário porque o perfil herdará a configuração padrão do plug-in Surefire; portanto, mesmo se você disser <excludedGroups/>ou <excludedGroups></excludedGroups>, o valor com.test.annotation.type.IntegrationTestserá usado.

Você também não pode usá- nonelo, pois deve ser uma interface no caminho de classe (o Maven verificará isso).

Notas:

  • A dependência para surefire-junit47é necessária apenas quando o Maven não muda automaticamente para o corredor JUnit 4. O uso do elemento groupsou excludedGroupsdeve acionar a chave. Veja aqui .
  • A maior parte do código acima foi retirada da documentação do plug-in Maven Failsafe. Consulte a seção "Usando categorias JUnit" nesta página .
  • Durante meus testes, descobri que isso funciona mesmo quando você usa @RunWith()anotações para executar suítes ou testes baseados em Spring.
John Dobie
fonte
18
Acho que há um erro no seu último fragmento pom.xml. você colou o mesmo snippet da fase "teste". ele ainda exclui os testes de integração e também não está vinculado a nenhuma fase final.
Alex
1
De fato, o último fragmento de pom é um erro de copiar e colar. Ele deve mostrar o plugin maven-failafe-plugin.
Paulo Merson 10/09
2
Então, qual deve ser o segundo xml então? : O
Liv
Você não precisa usar o truque (última mágica com Serializable) se usar o perfil padrão do Maven
user831217
Essa deve ser realmente a resposta aceita, porque na verdade é uma solução para a pergunta, em vez de um debate filosófico sobre onde colocar diferentes testes.
Bwvolleyball 29/03
40

Usamos o Maven Surefire Plugin para executar testes de unidade e o Maven Failsafe Plugin para executar testes de integração. Os testes de unidade seguem as **/Test*.java **/*Test.java **/*TestCase.javaconvenções de nomenclatura, testes de integração - **/IT*.java **/*IT.java **/*ITCase.java. Então, na verdade, é a sua opção número três.

Em alguns projetos, usamos o TestNG e definimos diferentes grupos de testes para integração / testes de unidade, mas isso provavelmente não é adequado para você.

lexicore
fonte
1
+1 para a combinação maven + surefire + failafe + junit. Eu não sabia que o Failafe executaria "IT *" automaticamente. Doce.
PapaFreud
13

Eu mudaria para o Junit4 apenas por tê-lo :)

Você pode separá-los em diferentes suítes de teste. Não sei como eles estão organizados no Junit3, mas no Junit4 deve ser fácil apenas criar conjuntos de testes e colocar todos os testes de unidade reais em um deles e usar um segundo conjunto para os testes de integração.

Agora defina uma configuração de execução para os dois conjuntos no eclipse e você pode executar facilmente um único conjunto. Esses conjuntos também podem ser iniciados a partir de um processo automatizado, permitindo que você execute os testes de unidade sempre que a fonte for alterada e talvez os testes de integração (se eles forem realmente grandes) apenas uma vez por dia ou uma vez por hora.

Janusz
fonte
9

O uso da anotação de mola IfProfileValue possibilita isso sem a necessidade de um plug-in ou configuração maven.

Anote as classes ou métodos de teste de integração usando o IfProfileValue

import org.springframework.test.annotation.IfProfileValue;

@IfProfileValue(name="test-groups", value="integration")
public class ExampleIntegrationTest{
    @Test
    public void longRunningServiceTest() throws Exception {
    }
} 

Para executar usando apenas testes de unidade:

mvn clean test

Para executar usando testes de integração e testes de unidade:

mvn clean test -Dtest-groups=integration

Além disso, "Executar todos os testes" em um IDE executaria apenas testes de unidade. Adicione -Dtest-groups=integrationargumentos à VM para executar testes de integração e unidade.

Mit Mehta
fonte
Essa abordagem é simples e agradável, mas o problema que encontro é que, por padrão, gostaria de executar todos os testes (incluindo testes de integração). Isso não é possível com essa abordagem, é?
Csalazar #
6

Não existe uma resposta certa. Como você explicou, existem várias maneiras de fazer isso que funcionarão. Eu fiz o esquema de nomeação de arquivos e dividi as coisas em diretórios diferentes.

Parece que dividir as coisas em diretórios diferentes pode funcionar melhor para você, e isso me parece um pouco mais claro, então eu me inclino para isso.

Acho que não tentaria anotações porque isso me parece mais refinado. Deseja realmente esses dois tipos de testes combinados no mesmo arquivo? Eu não faria.

ndp
fonte