Há duas questões que precisamos analisar aqui.
A primeira é que você parece observar todos os seus testes da perspectiva do teste de unidade. Os testes de unidade são extremamente valiosos, mas não são os únicos tipos de testes. Na verdade, os testes podem ser divididos em várias camadas diferentes, desde testes de unidade muito rápidos a testes de integração menos rápidos , até testes de aceitação ainda mais lentos . (Pode haver ainda mais camadas divididas, como testes funcionais .)
A segunda é que você está misturando chamadas para código de terceiros com sua lógica de negócios, criando desafios de teste e possivelmente tornando seu código mais frágil.
Os testes de unidade devem ser rápidos e devem ser executados com frequência. A zombaria de dependências ajuda a manter esses testes em execução rapidamente, mas pode introduzir furos na cobertura se a dependência mudar e a simulação não mudar. Seu código pode ser quebrado enquanto seus testes ainda são executados em verde. Algumas bibliotecas de simulação irão alertá-lo se a interface da dependência mudar, outras não.
Os testes de integração, por outro lado, são projetados para testar as interações entre componentes, incluindo bibliotecas de terceiros. As zombarias não devem ser usadas nesse nível de teste, porque queremos ver como o objeto real interage. Como estamos usando objetos reais, esses testes serão mais lentos e não os executaremos tão frequentemente quanto nossos testes de unidade.
Os testes de aceitação olham para um nível ainda mais alto, testando se os requisitos para o software são atendidos. Esses testes são executados em todo o sistema completo que seria implantado. Mais uma vez, nenhuma zombaria deve ser usada.
Uma orientação que as pessoas consideraram valiosa em relação às zombarias é não zombar dos tipos que você não possui . A Amazon é proprietária da API do S3 para garantir que ela não seja alterada abaixo deles. Você, por outro lado, não possui essas garantias. Portanto, se você zombar da API do S3 em seus testes, ela pode alterar e quebrar seu código, enquanto todos os testes são exibidos em verde. Então, como fazemos o código de teste unitário que usa bibliotecas de terceiros?
Bem, nós não. Se seguirmos a diretriz, não podemos zombar de objetos que não possuímos. Mas ... se possuímos nossas dependências diretas, podemos zombar delas. Mas como? Criamos nosso próprio wrapper para a API S3. Podemos fazer com que ela se pareça muito com a API S3, ou podemos atender melhor às nossas necessidades (de preferência). Podemos até torná-lo um pouco mais abstrato, digamos, em PersistenceService
vez de um AmazonS3Bucket
.PersistenceService
seria uma interface com métodos como #save(Thing)
e #fetch(ThingId)
, os tipos de métodos que gostaríamos de ver (estes são exemplos, você pode realmente querer métodos diferentes). Agora podemos implementar uma PersistenceService
API S3 (digamos a S3PersistenceService
), encapsulando-a para longe do código de chamada.
Agora, o código que chama a API S3. Precisamos substituir essas chamadas por chamadas para um PersistenceService
objeto. Usamos injeção de dependência para passar nossa PersistenceService
para o objeto. É importante não pedir um S3PersistenceService
, mas pedir um PersistenceService
. Isso nos permite trocar a implementação durante nossos testes.
Todo o código que costumava usar a API S3 agora usa agora o nosso PersistenceService
, e o nosso S3PersistenceService
agora faz todas as chamadas para a API S3. Em nossos testes, podemos zombar PersistenceService
, já que o possuímos, e usá-lo para garantir que nosso código faça as chamadas corretas. Mas agora isso deixa como testarS3PersistenceService
. Ele tem o mesmo problema de antes: não podemos testá-lo sem chamar o serviço externo. Então ... nós não fazemos testes unitários. Nós poderia zombar as dependências S3 API, mas isto nos daria pouco ou nenhuma confiança adicional. Em vez disso, temos que testá-lo em um nível superior: testes de integração.
Isso pode parecer um pouco preocupante, dizendo que não devemos testar uma parte do nosso código, mas vejamos o que realizamos. Tínhamos um monte de código em todo o lugar que não podíamos testar em unidade que agora pode ser testado em unidade através doPersistenceService
. Temos nossa confusão de bibliotecas de terceiros confinada a uma única classe de implementação. Essa classe deve fornecer a funcionalidade necessária para usar a API, mas não possui nenhuma lógica comercial externa anexada a ela. Portanto, uma vez escrito, deve ser muito estável e não deve mudar muito. Podemos confiar em testes mais lentos que não executamos com frequência porque o código é estável.
O próximo passo é escrever os testes de integração para S3PersistenceService
. Eles devem ser separados por nome ou pasta, para que possamos executá-los separadamente de nossos testes rápidos de unidade. Os testes de integração geralmente podem usar as mesmas estruturas de teste que os testes de unidade, se o código for suficientemente informativo; portanto, não precisamos aprender uma nova ferramenta. O código real para o teste de integração é o que você escreveria para sua Opção 1.