Eu tenho andado em círculos, tentando descobrir a melhor maneira de testar a unidade de uma biblioteca cliente da API que estou desenvolvendo. A biblioteca possui uma Client
classe que basicamente possui um mapeamento 1: 1 com a API e uma Wrapper
classe adicional que fornece uma interface mais amigável na parte superior da Client
.
Wrapper --> Client --> External API
Escrevi pela primeira vez vários testes contra os dois Client
e Wrapper
, efetivamente, apenas testando que eles encaminham para as funções apropriadas de qualquer operação ( Wrapper
opera Client
e Client
opera em uma conexão HTTP). Comecei a me sentir desconfortável com isso, no entanto, porque sinto que estou testando a implementação dessas classes, e não a interface. Em teoria, eu poderia alterar as classes para ter outra implementação perfeitamente válida, mas meus testes falhariam porque as funções que eu esperava ser chamadas não estavam sendo chamadas. Isso soa como testes frágeis para mim.
Depois disso, pensei na interface das classes. Os testes devem verificar se as classes realmente fazem o trabalho que devem fazer, e não como o fazem. Então, como posso fazer isso? A primeira coisa que vem à mente é remover as solicitações externas da API. No entanto, estou nervoso por simplificar demais o serviço externo. Muitos dos exemplos de APIs stubbed que eu vi apenas fornecem respostas enlatadas, o que parece ser uma maneira muito fácil de testar apenas se seu código é executado corretamente na API falsa. A alternativa é zombar do serviço, o que é inviável e precisaria ser atualizado sempre que o serviço real mudar - isso parece exagero e perda de tempo.
Por fim, li isso de outra resposta nos programadores SE :
O trabalho de um cliente remoto da API é emitir determinadas chamadas - nem mais nem menos. Portanto, seu teste deve verificar se emite essas chamadas - nem mais nem menos.
E agora estou mais ou menos convencido - ao testar Client
, tudo o que preciso é fazer as solicitações corretas para a API (é claro, sempre há a possibilidade de a API mudar, mas meus testes continuam a passar - mas isso é onde os testes de integração seriam úteis). Como Client
é apenas um mapeamento 1: 1 com a API, minha preocupação antes sobre a alteração de uma implementação válida para outra não se aplica realmente - há apenas uma implementação válida para cada método de Client
.
No entanto, ainda estou preso à Wrapper
turma. Eu vejo as seguintes opções:
Eu esqueço a
Client
classe e apenas testo se os métodos apropriados são chamados. Dessa forma, estou fazendo o mesmo que acima, mas tratandoClient
como um substituto para a API. Isso me coloca de volta onde comecei. Mais uma vez, isso me dá a sensação desconfortável de testar a implementação, não a interface. AWrapper
poderia muito bem ser implementado usando um cliente completamente diferente.Eu crio uma zombaria
Client
. Agora eu tenho que decidir até onde ir com a zombaria - criar uma zombaria completa do serviço exigiria muito esforço (mais trabalho do que foi feito na própria biblioteca). A API em si é simples, mas o serviço é bastante complexo (é essencialmente um armazenamento de dados com operações nesses dados). E, novamente, terei que manter minha zombaria sincronizada com o realClient
.Acabei de testar se as solicitações HTTP apropriadas estão sendo feitas. Isso significa que a
Wrapper
chamada será feita através de umClient
objeto real para fazer essas solicitações HTTP, portanto, na verdade, não estou testando isso isoladamente. Isso faz com que seja um teste de unidade terrível.
Portanto, não estou particularmente feliz com nenhuma dessas soluções. O que você faria? Existe um caminho certo para fazer isso?