Testes de Contratos com PACT #2 - Consumer Driven Contract | Zup
Testes de Contratos com PACT #2 – Consumer Driven Contract
No artigo anterior fizemos uma breve explicação sobre testes integrados e seus desafios no ambiente de desenvolvimento de software. Neste artigo, explicaremos o conceito do Consumer Driven Contract e como ele pode ser uma alternativa aos testes integrados tradicionais (end to end).
Antes de mergulharmos no conceito do CDC, vamos refrescar a memória: qual é o problema de fazer um teste em ambiente integrado? O teste integrado envolve custos adicionais de infraestrutura — é mais lento, uma vez que os serviços devem estar disponíveis, requer toda infraestrutura dependente dos serviços (banco de dados, filas MQ, etc).
Qual é o problema de testar a integração realizando um mock da chamada pelo lado de quem a consome?
Mockar (simular) a chamada não te dará certeza de que a integração é realizada conforme seu Mock. Portanto, mesmo que seu teste retorne positivo, não há certeza que a implementação do outro lado já não reflita conforme o ambiente integrado. Conforme imagem abaixo, o teste, tanto mockado quanto integrado, é baseado em expectativas que são um mundo paralelo entre o ambiente integrado e o ambiente produtivo.
Onde entra o CDC? Vamos entender primeiro sua literatura: Ian Robinson redigiu um artigo onde explica toda a terminologia do CDC. Trazendo de uma forma mais simples, em qualquer teste integrado temos os atores que realizam interações: o Provider e o Consumer. Onde um provider é quem provê algum serviço e consumer é quem irá consumir esse serviço, certo?
No caso do CDC (Contrato Orientado ao Consumidor) o consumer 'descreve' suas expectativas de como essa comunicação será realizada; podemos chamá-las de asserções, expectativas de consumo, ou ainda: requisição, informações e dados da resposta — isso é o que chamamos de contrato.
Do lado do provedor, o contrato é validado conforme descrito pelo consumidor. A ideia por trás do CDC é envolver os consumidores da futura API na criação dela (com expectativas). As alterações na API serão conduzidas pelos consumidores, pois eles possuem um pacto de consumo com quem provê, ambos devem realizar as alterações em conjunto e assim garantirem a integração.
Ok, mas como ele resolve os testes integrados? Imagine que o consumer, ao codificar suas expectativas via código em forma de testes unitários e executar esse teste, criará de fato um mock do serviço provedor; o mock do serviço testará suas expectativas, requisição, dados de entrada e saída, etc.
Se tudo for feito de forma correta, será gerado um arquivo de contrato, um arquivo de notação o qual podemos enviar para o provider validá-lo. O provider, por sua vez, executará esse contrato na mesma forma, teste unitário, no qual ele não necessita prover todas as suas integrações, podendo "mockar" as dependências como sua infraestrutura de banco de dados, por exemplo. O objetivo é a validação da 'assinatura' da integração: requisição, resposta e dados da integração.
Segue uma imagem que ilustra bem essa interação:
A partir daqui, o 'ambiente integrado' não é mais necessário. Sendo possível incluir os passos descritos como um teste automatizado dos dois lados — do consumer e do provider — e incluí-los em suas rotinas de CI. Caso o contrato esteja correto, sabemos que a integração está sendo feita de forma correta e o contrato não foi quebrado. O mesmo servirá para futuras alterações: toda vez que os testes unitários forem executados devemos garantir que o contrato continue válido.
Agora vamos adentrar as vantagens dessa abordagem para, em seguida, entendermos como o PACT nos ajuda com a tarefa de implementar o CDC:
Remove a necessidade do ambiente integrado para testes de integração.
Mantemos o isolamento dos testes conforme pirâmide de testes.
Feedback de futuras implementações ou visibilidade do rompimento do contrato por algum dos lados.
Implementação mais segura de suas integrações para o ambiente produtivo, uma vez que elas estarão testadas e validadas sob sua comunicação.
Agora que entendemos os desafios dos testes integrados, o conceito do CDC, vamos entender como o PACT nos ajuda na implementação do mesmo.
O PACT Framework
O PACT é um framework feito inicialmente em Ruby que absorve todo o conceito de CDC. Foi amplamente difundido pela comunidade e atualmente ganhou versões para diversas linguagens de programação, facilitando a implementação para os desenvolvedores. As terminologias são as mesmas descritas acima para seu uso, mas o PACT tem mais algumas facilidades no quesito automatização da validação dos contratos.
Vamos entender na prática como isso funciona e como pode ser implementado?
No site do PACT encontramos uma documentação bem redigida sobre todo seu conceito e todas as ferramentas que podem ser utilizadas para realizar as validações do contrato.
Hoje, quero dar atenção ao GIF animado logo abaixo, e que pode ser encontrado completo aqui, ele que explica visualmente e de forma bem resumida como o PACT funciona.
Fonte: pactflow.io
O PACT implementa o conceito de CDC em forma de testes unitários BDD (Behavior Driven Development). Quando escritos, os testes são executados simulando a integração que deverá ser executada — gerando o contrato, validando sua assinatura e garantindo a integração — sem a necessidade de subir projetos em algum ambiente integrado.
Como vantagens, o PACT possui uma sintaxe muito simples, chamada de PACT DSL (acrônimo para domain-specific language). Para a escrita das expectativas, fica bem intuitivo, então imagine um teste unitário escrito em DSL: você provavelmente vai encontrar algo do tipo "enviando uma requisição para a URL $URL com os dados de requisição $request, espero receber um HTTP status $http_status, e um body $body".
Fique tranquilo(a), em breve teremos um hands on do PACT para demonstrar como ele funciona! Por agora, vamos focar nos conceitos da ferramenta.
Um dos recursos do PACT é o PACT Broker, uma ferramenta que fica entre os providers e consumers versionando contratos e administrando as verificações. Essa é a grande sacada do PACT, ao invés do consumer e provider ficarem trocando seus contratos, eles enviam para o Broker que fica entre as aplicações, ou seja, para realizar os testes de contratos, ambos se comunicam com o Broker.
O PACT Broker está disponível em container docker e é bem simples de utilizar, no próximo artigo trarei exemplos práticos de utilização com um cenário bem simples de integração.
Versionamento de contratos
O PACT Broker tem um versionamento de contratos bem inteligente no qual é verificado se a submissão do contrato não é igual a uma versão já enviada anteriormente. Existem dois versionamentos: o versionamento do contrato que o Consumer e o Provider enviam para o Broker e a versão que o próprio Broker gera garantindo a unicidade.
Imagine um cenário que duas aplicações Consumers enviam contratos similares, eles ganharão um apontamento para a versão do PACT Broker. Neste caso, ganhamos agilidade para testar contratos ambíguos pela parte do Provider.
Pact Framework está disponível para linguagens: Ruby, Java, .Net, Javascript, Go, Python, Swift e PHP.
O Pact Matrix é uma feature do Pact Broker onde temos o de-para das versões dos contratos e suas validações. Com ele podemos criar um processo automatizado via CI para validar se nossa integração está coesa e testada antes de enviá-la para o ambiente produtivo. É aqui que iremos buscar a saúde de nossas integrações.
Na imagem acima temos o nome do Consumer, sua versão, a data e hora de publicação, o nome do Provider, a versão e uma TAG que o Provider enviou.
A TAG facilita na identificação de uma integração, ao invés de usarmos o número da versão, podemos validar obtendo a última versão disponível pela TAG via a ferramenta CLI do PACT, o CLI can-i-deploy. Assim fica mais fácil achar a última versão testada da sua integração. Por último a data da verificação e seu status de cor verde ou vermelho. Novamente, essa é uma interface web do Broker mas a interação é feita pela ferramenta can-i-deploy e pode ser automatizada via CI.
Sobre o Can I Deploy
O can-i-deploy é uma ferramenta CLI do PACT que abstrai o conceito de obter a saúde da integração no Pact Broker, ela consulta o PACT Matrix e te responde um OK, NOK. Ou seja, se a integração e seus participantes (Provider e Consumer) estão saudáveis ou não.
A vantagem do can-i-deploy encontra-se na automatização de um "flow" de validação de contratos. Podemos criar um fluxo onde geramos o contrato, publicamos no Broker, o provider valida o contrato e, por último, obtemos o resultado dessa integração via can-i-deploy.
Agora que entendemos que o PACT tem features interessantes, como utilizá-las para testar nossas integrações e remover o ambiente integrado?
Essa abordagem ficará no próximo capítulo, mais hands-on e veremos o poder do PACT e como usá-lo. Vejo vocês no próximo capítulo?
https://docs.pact.io/pact_broker/can_i_deploy
https://github.com/pact-foundation/pact-broker-docker
https://www.itnation.lu/improve-the-design-and-testing-of-your-micro-services-through-consumer-driven-contract-tests-part-1-3/
https://www.itnation.lu/rdv-tech-agile-partner-consumer-driven-contract-testing-made-simple-with-pact-part-2-3/
https://www.itnation.lu/pact-broker-the-missing-piece-of-your-consumer-driven-contract-approach-part-3-3/