A única lógica real está na sintaxe da consulta para a API externa. Eu não quero testar se ele consulta a API, quero testar se ele a consulta de forma que os dados corretos sejam retornados. Por exemplo, alguns pseudo-códigos:
function retrieve_related_data(id)
{
query = "[potentially long, syntactically complex query that
uses param id to get some data]";
results = api_wrapper.query(query);
return results;
}
Um exemplo mais concreto com uma API inventada:
function retrieveLifeSupportingObjectsWithinRegion(id)
{
query = "
within region(" + id + ") as r
find objects matching hydration>0 and temp_range has 75
send name, id, relative(position, r)
";
results = astronomicalObjectApiWrapper.query(query);
return results;
}
A consulta está em uma sintaxe personalizada da API e é complexa e há várias maneiras de obter resultados iguais ou semelhantes. O objetivo da função não é obter dados identificados por, id
mas encontrar um subconjunto de outros dados com base em um relacionamento difuso com os dados identificados por id
que também atende a alguns outros requisitos. Os outros requisitos são sempre os mesmos, independentemente, id
mas podem mudar com o tempo à medida que o sistema é modificado. Por exemplo, se a API de exemplo adicionou suporte para informações de gravidade, podemos alterar a consulta para também usar a gravidade para refinar os resultados. Ou talvez tenhamos uma maneira mais eficiente de verificar o intervalo de temperatura, mas isso não altera os resultados.
O que eu quero testar é que, para uma determinada entrada, id
o conjunto correto de dados seja retornado. Desejo testar isso para que, se alguém atrapalhar a consulta de forma que não retorne mais os dados corretos com base na id
falha, mas também quero que as pessoas possam modificar a consulta para refiná-la sem precisar modificar também o teste.
Opções que eu considerei:
Eu poderia stub a API, mas isso seria muito simples (verifique se
id
está presente na consulta e, em seguida, retorne um conjunto de dados esperado, se for, ou um conjunto inesperado, se não for), muito frágil (verifique se a string de consulta está exatamente o que está na função), ou muito complexa (verificação de que a consulta usada é sintaticamente correto e irá resultar nos dados corretos estão sendo devolvidos).Eu poderia enviar a consulta para a API real, mas os resultados esperados podem mudar com o tempo, à medida que os dados no sistema externo são alterados, fora do controle do sistema de teste.
Eu poderia olhar para configurar uma instalação de teste da API real, a fim de controlar os dados que ela possui, mas isso é muito esforço.
Estou me inclinando para a segunda posição e tornando isso mais um teste de integração que não é executado com frequência e vendo com que frequência as alterações nos dados do sistema externo fazem com que o teste seja interrompido. Eu acho que seria mais simples por enquanto, mas estou me perguntando se existem alternativas nas quais não estou pensando ou melhores maneiras de resolver esse problema. Qualquer conselho seria apreciado.
fonte
Respostas:
Pode parecer que, ao validar a resposta da API externa, estaríamos testando nossa função, mas isso não seria totalmente verdadeiro. De alguma forma, estaríamos testando a API externa e o ambiente em que a API está sendo executada.
Nossos testes devem ser direcionados para garantir o comportamento esperado do código que escrevemos, e não do código de terceiros.
Até certo ponto, temos que confiar no bom funcionamento das APIs e bibliotecas nas quais confiamos. Por exemplo, geralmente não testamos os componentes da estrutura que implementamos.
Por que eu digo isso?
O que seria testado aqui? Como você disse, os dados e sua correção não estão sob nosso controle; portanto, estaríamos restringindo o sucesso da fase de teste a um agente externo que não temos nenhum controle. Esses testes são candidatos a tornarem - se não determinísticos e, definitivamente, não queremos esse tipo de teste em nosso pipeline de construção .
Uma preocupação diferente é validar o contrato. Eu consideraria bastante útil um teste de contrato 1 para garantir que a integração ainda funcione conforme o esperado, antes de qualquer release ou implantação.
E se a consulta estiver ok, mas os dados estiverem incorretos devido a erros na API? Não apenas os dados estão fora de nosso controle. A lógica também é.
A implementação de testes funcionais ou de ponta a ponta pode ajudar aqui. Você pode abordar esses testes para validar certos caminhos de execução, de modo que, se as APIs retornarem dados incorretos, isso provavelmente causará comportamentos e saídas inesperados. Por outro lado, eu esperaria que a API gerasse erros se minhas consultas tivessem um formato incorreto.
Sugiro implementar uma ferramenta para esse fim. Pode ser tão simples quanto:
Ou algo mais sofisticado. Por exemplo, um cliente autônomo.
De qualquer forma, a função em questão vale bem dois tipos de testes:
Teste de unidade. Como você disse, você precisa stubb da API externa, mas esse é o objetivo de testes de unidade. Testando nosso código isolando as dependências.
Teste de integração. Verifique se o código não apenas envia a solicitação correta, mas também lida com o conteúdo da resposta, erros, redirecionamentos etc. Faça testes para todos esses casos, mas não os dados .
Nota lateral: Sua pergunta é semelhante a como você testa as instruções SQL do aplicativo?
Questões relacionadas :
1: você pode estar interessado na resposta da @ DocBrown sobre este tópico
fonte
Eu vi verificações de unidade que verificam se a string de consulta gerada corresponde a um valor esperado.
Contudo. Isso foi na minha opinião se uso limitado. A sintaxe da consulta era complicada, possivelmente com erros, portanto, havia A infinitas possibilidades de verificação e B, mesmo que a sequência fosse 'corretamente' gerada, resultados inesperados poderiam ser retornados no ambiente ativo.
Eu acho que você está certo em escolher sua opção 2. executar testes de integração na instância ao vivo.
Desde que não sejam destrutivos, esses são os primeiros testes que você deve escrever, pois capturam, embora não identifiquem a causa de qualquer erro.
A opção 3 'implantar uma instância de teste com dados fictícios' é superior. Mas isso não afeta a gravação do teste, pois você pode apontar os mesmos testes no servidor de teste se e quando se tornar um bom uso do tempo para implantar um.
fonte
Depende da API, mas se possível, vá para a opção 3 (instância de teste particular).
O stubbing da API (opção 1) é a pior opção, pelas razões mencionadas, e seguir essa rota provavelmente fará mais mal do que bem (muito tempo perdido).
A execução na API real (opção 2) torna os testes difíceis e pouco confiáveis e, após alguns falsos positivos, as pessoas param de usá-los. Não apenas os dados podem mudar, mas o serviço também pode estar inativo. Na minha opinião, isso é semelhante a não ter testes para as consultas e depender de testes de integração / sistema para encontrar os problemas. Dito isto, se os dados da API raramente mudam e a própria API está quase sempre ativa, essa pode ser uma opção viável. A maioria das APIs não se encaixa nessa descrição.
Eventualmente, tudo se resume à importância e complexidade dessas consultas: se houver mais do que algumas, e algumas delas forem complexas o suficiente para que você sinta necessidade de testá-las, eu investiria o esforço de configurar uma instância privada para teste. . Pagará por si mesmo, assim como outros testes de unidade.
fonte