No meu projeto atual, estou tendo dificuldades para encontrar uma boa solução para criar testes de integração escaláveis que não tenham efeitos colaterais. Um pequeno esclarecimento sobre a propriedade livre de efeitos colaterais: é principalmente sobre o banco de dados; não deve haver nenhuma alteração no banco de dados após a conclusão dos testes (o estado deve ser preservado). Talvez a escalabilidade e a preservação do estado não se combinem, mas eu realmente quero buscar uma solução melhor.
Aqui está um teste de integração típico (esses testes tocam a camada do banco de dados):
public class OrderTests {
List<Order> ordersToDelete = new ArrayList<Order>();
public testOrderCreation() {
Order order = new Order();
assertTrue(order.save());
orderToDelete.add(order);
}
public testOrderComparison() {
Order order = new Order();
Order order2 = new Order();
assertFalse(order.isEqual(order2);
orderToDelete.add(order);
orderToDelete.add(order2);
}
// More tests
public teardown() {
for(Order order : ordersToDelete)
order.delete();
}
}
Como se pode imaginar, essa abordagem produz testes extremamente lentos. E, quando aplicado a todos os testes de integração, leva cerca de 5 segundos para testar apenas uma pequena parte do sistema. Eu posso imaginar esse número aumentando quando a cobertura é aumentada.
Qual seria outra abordagem para escrever esses testes? Uma alternativa em que posso pensar é ter variáveis globais (dentro de uma classe) e todos os métodos de teste compartilham essa variável. Como resultado, apenas alguns pedidos são criados e excluídos; resultando em testes mais rápidos. No entanto, acho que isso apresenta um problema maior; os testes não são mais isolados e fica cada vez mais difícil entendê-los e analisá-los.
Pode ser que os testes de integração não sejam executados com a mesma frequência que os testes de unidade; portanto, baixo desempenho pode ser aceitável para eles. De qualquer forma, seria ótimo saber se alguém encontrou alternativas para melhorar a escalabilidade.
Esse é o eterno problema que todos enfrentam enquanto escrevem testes de integração.
A solução ideal, principalmente se você estiver testando a produção, está abrindo uma transação na configuração e revertendo-a na desmontagem. Eu acho que isso deve atender às suas necessidades.
Onde isso não for possível, por exemplo, quando você estiver testando o aplicativo a partir da camada do cliente, outra solução é usar um banco de dados em uma máquina virtual e tirar um instantâneo na configuração e voltar a ele em desmontagem (não demore o tempo que você espera).
fonte
Os testes de integração sempre devem ser executados na configuração da produção. No seu caso, significa que você deve ter o mesmo banco de dados e servidor de aplicativos. Obviamente, por uma questão de desempenho, você pode optar por usar um banco de dados na memória.
O que você nunca deve fazer é estender o escopo da transação. Algumas pessoas sugeriram assumir o controle da transação e revertê-la após os testes. Ao fazer isso, todas as entidades (supondo que você esteja usando o JPA) permanecerão anexadas ao contexto de persistência durante a execução do teste. Isso pode resultar em alguns erros muito desagradáveis que são muito difíceis de encontrar .
Em vez disso, você deve limpar o banco de dados manualmente após cada teste através de uma biblioteca como JPAUnit ou semelhante a essa abordagem (limpe todas as tabelas usando JDBC).
Como seus problemas de desempenho, você não deve executar os testes de integração em todas as versões. Deixe seu servidor de integração contínua fazer isso. Se você usa o Maven, pode aproveitar o plug-in à prova de falhas , que permite separar seus testes em testes de unidade e integração.
Além disso, você não deve zombar de nada. Lembre-se de que você está testando a integração, ou seja, testando o comportamento no ambiente de execução em tempo de execução.
fonte
Sobre escalabilidade
Eu já tive esse problema algumas vezes antes, que os testes de integração estavam demorando muito para serem executados e não eram práticos para um único desenvolvedor executar continuamente em um ciclo de feedback apertado de alterações. Algumas estratégias para lidar com isso são:
Tente combinar essas técnicas para obter um efeito maior.
fonte
Para fins de teste, usamos uma implantação baseada em arquivo de um banco de dados SQLite (basta copiar um recurso). Isso foi feito para que também pudéssemos testar as migrações de esquema. Tanto quanto sei, as alterações do esquema não são transacionais, portanto, não serão revertidas depois que uma transação for abotada. Além disso, não ter que depender do suporte a transações para a configuração de teste permite testar o comportamento das transações do seu aplicativo corretamente.
fonte