É uma prática recomendada impor uma ordem de execução para testes de unidade?

84

Estou escrevendo testes para um projeto que consiste em vários submódulos. Cada caso de teste que escrevi é executado independentemente um do outro e eu limpo todos os dados entre os testes.

Embora os testes sejam executados de forma independente, estou pensando em impor uma ordem de execução, pois alguns casos exigem mais de um submódulo. Por exemplo, um submódulo está gerando dados e outro está executando consultas nos dados. Se o submódulo que gera os dados contiver um erro, o teste para o submódulo de consulta também falhará, mesmo que o próprio submódulo funcione bem.

Não posso trabalhar com dados fictícios, pois a principal funcionalidade que estou testando é a conexão com um servidor remoto de caixa preta, que obtém apenas os dados do primeiro submódulo.

Nesse caso, não há problema em impor uma ordem de execução para os testes ou é uma má prática? Sinto que há um cheiro nessa configuração, mas não consigo encontrar uma maneira melhor de contornar.

edit: a pergunta é de Como estruturar testes onde um teste é a configuração de outro teste? como o teste "anterior" não é uma instalação, mas testa o código que executa a instalação.

Ali Rasim Kocal
fonte
123
Se você estiver testando a conexão com um servidor remoto, eles, por definição, não são testes de unidade.
Telastyn
9
A primeira resposta me confundiu aqui, porque no seu título você disse: "É uma prática ruim?" e no resumo da sua pergunta, você escreveu "está tudo bem?" Qualquer pessoa que responda sim ou não vai confundir um deles!
Liath
8
Parece que você está criando um conjunto de testes de integração. Mesmo para esse teste, não deve confiar em outros testes.
Pelicano de vôo baixo
17
Se o pedido for importante, provavelmente você está fazendo errado.
Mark Rogers

Respostas:

236

Não posso trabalhar com dados fictícios, pois a principal funcionalidade que estou testando é a conexão com um servidor remoto de caixa preta, que obtém apenas os dados do primeiro submódulo.

Esta é a parte chave para mim. Você pode falar sobre "testes de unidade" e eles "executando independentemente um do outro", mas todos parecem que dependem desse servidor remoto e do "primeiro submódulo". Então, tudo soa bem acoplado e depende do estado externo. Como tal, você está de fato escrevendo testes de integração. A execução desses testes em uma ordem específica é bastante normal, pois são altamente dependentes de fatores externos. Uma execução de teste ordenada, com a opção de sair antecipadamente da execução de teste, se algo der errado, é perfeitamente aceitável para testes de integração.

Mas também vale a pena dar uma nova olhada na estrutura do seu aplicativo. Ser capaz de simular o primeiro submódulo e o servidor externo permitiria que você escrevesse testes de unidade verdadeiros para todos os outros submódulos.

David Arno
fonte
14
Sem mencionar que alguns testes precisam verificar especificamente se o comportamento esperado ocorre quando o servidor remoto não está disponível.
Alexander Alexander
2
Ou, talvez, você esteja realmente pretendendo escrever testes de integração e, dessa forma, zombar dos dados não alcançará o que você está tentando realizar com esses testes.
precisa saber é o seguinte
10
O problema é mais provável que o Junit tenha "unidade" em seu nome.
Thorbjørn Ravn Andersen
7
@ ThorbjørnRavnAndersen Exatamente. As pessoas escrevem naturalmente testes de integração, em vez de testes de unidade, porque os testes de integração são muito mais úteis e muito menos difíceis de escrever do que os testes de unidade "reais". Mas como as estruturas de teste populares foram nomeadas com base no conceito de testes de unidade, o termo foi cooptado e passou a significar "qualquer teste automatizado" na linguagem moderna.
Mason Wheeler
1
@MasonWheeler Ou mesmo cooptado por gerentes não técnicos para significar teste de aceitação.
TKK
32

Sim, é uma prática ruim.

Geralmente, um teste de unidade destina-se a testar uma única unidade de código (por exemplo, uma única função baseada em um estado conhecido).

Quando você deseja testar uma cadeia de eventos que podem ocorrer na natureza, deseja um estilo de teste diferente, como um teste de integração. Isso é ainda mais verdadeiro se você estiver dependendo de um serviço de terceiros.

Para fazer testes unitários como esse, é necessário descobrir uma maneira de injetar os dados fictícios, por exemplo, implementar uma interface de serviço de dados que espelha a solicitação da Web, mas retorna dados conhecidos de um arquivo de dados fictício local.

Paulo
fonte
8
Acordado. Eu acho que essa confusão decorre do fato de que muitas pessoas têm uma idéia de que os testes de integração precisam ser de ponta a ponta e usam "teste de unidade" para se referir a qualquer teste que teste apenas uma camada .
Autophage
8
@ autophage: Definitivamente concordo com isso. Na verdade eu concordo com ele tanto que eu regularmente encontrar-me cair na mesma armadilha , apesar de concordar que é uma armadilha 😂
Leveza raças em órbita
16

A ordem de execução imposta que você propõe apenas faz sentido se você também interromper a execução de teste após a primeira falha.

Interromper a execução do teste na primeira falha significa que cada execução pode descobrir apenas um único problema e não pode encontrar novos problemas até que todos os problemas anteriores tenham sido corrigidos. Se o primeiro teste a ser executado encontrar um problema que leva um mês para ser corrigido, durante esse mês efetivamente nenhum teste será executado.

Se você não interromper a execução do teste na primeira falha, a ordem de execução forçada não comprará nada, porque cada teste com falha precisa ser investigado de qualquer maneira. Mesmo que apenas para confirmar que o teste no submódulo de consulta está falhando devido à falha que também foi identificada no submódulo de geração de dados.

O melhor conselho que posso dar é escrever os testes de maneira que seja fácil identificar quando uma falha em uma dependência está causando a falha do teste.

Bart van Ingen Schenau
fonte
7

O cheiro a que você está se referindo é a aplicação do conjunto errado de restrições e regras aos seus testes.

Os testes de unidade geralmente são confundidos com "testes automatizados" ou "testes automatizados por um programador".

Os testes de unidade devem ser pequenos, independentes e rápidos.

Algumas pessoas leem incorretamente isso como "testes automatizados escritos por um programador devem ser pequenos independentes e rápidos" . Mas isso significa simplesmente que, se seus testes não são pequenos, independentes e rápidos, eles não são testes de unidade e, portanto, algumas das regras para testes de unidade não devem, não podem ou não devem ser aplicadas para seus testes. Um exemplo trivial: você deve executar seus testes de unidade após cada compilação, o que não deve ser feito para testes automatizados que não são rápidos.

Embora seus testes não sejam testes de unidade, você pode pular uma regra e ter alguma interdependência entre os testes, mas também descobriu que existem outras regras que você pode ter perdido e precisará reintroduzir - algo para o escopo de outra pergunta .

Peter
fonte
6

Como observado acima, o que você está executando parece ser um teste de integração, mas você afirma que:

Por exemplo, um submódulo está gerando dados e outro está executando consultas nos dados. Se o submódulo que gera os dados contiver um erro, o teste para o submódulo de consulta também falhará, mesmo que o próprio submódulo funcione bem.

E este pode ser um bom lugar para começar a refatoração. O módulo que executa consultas nos dados não deve depender de uma implementação concreta do primeiro módulo (geração de dados). Em vez disso, seria melhor injetar uma interface contendo os métodos para acessar esses dados e isso pode ser zombado para testar as consultas.

por exemplo

Se você tem:

class Queries {

    int GetTheNumber() {
        var dataModule = new Submodule1();
        var data = dataModule.GetData();
        return ... run some query on data
    }
}

Em vez disso, prefira:

interface DataModule {
    Data GetData();
}


class Queries {

    IDataModule _dataModule;

    ctor(IDataModule dataModule) {
       _dataModule = dataModule;
    }

    int GetTheNumber() {
        var data = _dataModule.GetData();
        return ... run some query on data
    }
}

Isso remove a dependência das consultas na fonte de dados e permite que você configure testes de unidade facilmente repetíveis para cenários específicos.

Paddy
fonte
6

As outras respostas mencionam que a ordem dos testes é ruim (o que é verdade na maioria das vezes), mas há uma boa razão para impor a ordem na execução do teste: garantir que seus testes lentos (por exemplo, testes de integração) sejam executados após os testes mais rápidos (testes que não dependem de outros recursos externos). Isso garante que você execute mais testes mais rapidamente, o que pode acelerar o ciclo de feedback.

Mike Holler
fonte
2
Eu estaria mais inclinado a investigar por que um determinado teste de unidade está sendo executado lentamente, em vez de impor um pedido. Os testes de unidade devem ser rápidos.
Robbie Dee
O OP diz que não pode trabalhar com dados fictícios para alguns desses testes. Isso significa algum tipo de acerto no banco de dados, atrasando todos os testes (mesmo alguns testes de unidade verdadeiros que devem ser executados com rapidez naturalmente). Se ele tiver outros testes que não exijam hits do banco de dados, eles executarão uma ordem de magnitude mais rapidamente do que qualquer coisa que exija hits do disco ou da rede.
Mike Holler
2
Vocês dois estão certos, eu acho; Robbie está certo de que os testes de unidade devem ser pequenos, rápidos e isolados das dependências; portanto, a ordem não importa e a ordem aleatória geralmente incentiva um melhor design, reforçando essa independência; e Mike está certo que executar testes mais rápidos primeiro é muito, muito bom para testes de integração . Como nas respostas acima, parte do problema é a terminologia dos testes de unidade versus integração.
WillC
@ MikeHoller Então eles não são testes de unidade. Realmente não deve haver confusão sobre o que são testes de unidade .
Robbie Dee #
@RobbieDee Eu estava apenas usando a terminologia que o OP estava usando. Entendo que esses não são verdadeiros testes de unidade. Se você quiser discutir sobre terminologia, traga-a com OP. (daí porque eu clarificado com "testes de unidade verdadeiros" no meu comentário anterior ")
Mike Holler