Cada teste de unidade deve poder ser executado independentemente de outros testes?

24

Digamos que você tenha testes para dois métodos de uma classe. O primeiro método reúne dados de outra camada e os coloca em algum tipo de armazenamento independente do tempo de execução (como uma tabela SQL), para que todos os dados manipulados por esse teste sejam codificados no teste. O segundo método é responsável por coletar dados de onde o primeiro método os deixou e transformá-los de alguma forma (cálculo, mover determinadas partes para outro lugar etc.).

Agora, este segundo método pode ter entradas codificadas como o primeiro, ou pode-se presumir que os dois testes seriam executados seqüencialmente e poderia continuar onde o primeiro teste parou, pegando os dados realmente armazenados pelo primeiro teste.

Se você seguisse a segunda opção, teria realmente uma boa idéia de que os dois métodos funcionam bem juntos; no entanto, se o 1º teste falhar, todos os testes depois dele falharão, tirando o benefício do teste, ajudando a isolar os bugs mais rapidamente.

Se você seguisse a primeira opção, cada método seria isolado e testado de forma independente, mas você nunca saberia realmente que eles podem realmente funcionar juntos corretamente.

Qual é a melhor opção aqui? Existe algum tipo de alternativa como ter um único teste para cada método isolado com codificação codificada e testes maiores que contêm os dois métodos em um?

Morgan Herlocker
fonte
2
Na verdade, eu gostaria de poder aleatoriamente facilmente a ordem dos testes de unidade toda vez que eles são executados. No momento, eles são executados em alguma ordem desconhecida, embora relativamente fixa.

Respostas:

11

Se você seguisse a primeira opção, cada método seria isolado e testado de forma independente, mas você nunca saberia realmente que eles podem realmente funcionar juntos corretamente.

Se seus métodos são verdadeiramente independentes, isso não deve importar. Seu segundo método deve:

a) Funcione corretamente quando apresentado com dados válidos.

b) Falha de maneira sensata e consistente quando apresentado com dados inválidos.

Igualmente, seu primeiro método deve fazer o mesmo. Portanto, contanto que você lide com os casos de erro, eles funcionarão juntos corretamente.

Se você deseja testar se os métodos funcionam corretamente juntos, isso é teste de integração, não teste de unidade.

ChrisF
fonte
27

Se os testes não puderem ser executados independentemente, eles não serão testes de unidade.

Um teste de unidade não deve depender de nenhum estado externo, como o conteúdo de uma tabela de banco de dados. Deve testar puramente uma unidade de código isoladamente.

Testes que alteram ou exigem um determinado estado são válidos, eles podem fazer parte de um teste de integração, por exemplo, e nesses casos é importante garantir que a configuração apropriada seja feita, mas esses não seriam testes de unidade. Nesse caso, eu ainda não recomendaria que um teste exigisse que outro fosse executado. Se você estiver nesse caso, provavelmente deve fatorar o código necessário em um método de configuração separado. Você pode ter um teste que apenas chama o código de configuração e verifica se nenhuma exceção é lançada, por exemplo, e outro teste que usa ativamente os dados configurados no método de configuração.

Steve
fonte
@ Steve, então neste exemplo, você diria: um teste para o método 1, um teste para o método 2 e um teste que executa 1 e 2 no mesmo teste?
Morgan Herlocker
2
Sim. os dois primeiros seriam testes de unidade, o terceiro soa como um teste de integração.
Steve
se você tiver o módulo do cliente e o módulo de pedidos e o pedido não puder ser criado sem relação com o cliente. Como você o testará independentemente do módulo do cliente: crie um registro do cliente no banco de dados com sql (insira no cliente) ou use Customer.createCustomer (). E o IMHO usar o segundo é melhor, pois você não precisa impelir nenhuma lógica no teste, mas funciona apenas se o seu teste de criação de clientes passar.
Dainius
@Dainius. Em um cenário de teste de unidade, você normalmente usaria objetos simulados para transmitir um cliente simulado ao seu módulo de pedido. Você está certo em não querer usar o sql neste caso.
Steve
parece que em qualquer cenário em que o método B depende do método A, quase sempre haverá um método C que chama A e, em seguida, chama B. Como esse é o caso, você pode testar A, B e C independentemente.
Morgan Herlocker
9

Tenho certeza de que agora parece bom ter o teste de unidade B, que depende do estado deixado pelo teste de unidade B. Mas considere daqui a um ano quando você tiver mil testes de unidade. Deseja realmente esperar dez minutos para que todo o seu conjunto de testes seja concluído toda vez que você precisar fazer uma alteração?

Depende do seu estilo de desenvolvimento, é claro, mas se você deseja alguma esperança de desenvolvimento decente orientado a testes, no qual você pode executar um teste individual várias vezes ao desenvolver um recurso, sugiro que você dê a cada teste a capacidade de se manter sozinho.

Steve Rukuts
fonte
1
Com +1 em Raskolnikov, não considerei o fato de que esse tempo seria muito grande depois que eu "executasse todos os testes" mais tarde.
Morgan Herlocker
3

Parece que você está falando sobre a configuração do teste, que pode ser realizada de várias maneiras. Você deseja uma cópia limpa dos dados de teste (chamados de acessórios) para cada teste, para que cada um deles não dependa um do outro.

Existem várias estruturas que permitem esse tipo de teste e ferramentas como o DBUnit que permitem criar e desmembrar estruturas de dados rapidamente no início e no final dos testes e suítes de testes.

TrueDub
fonte