Test Doubles 101 — Introdução à Fakes, Mocks, Stubs e afins
Imagine que você precisa validar o funcionamento de sua aplicação em um determinado cenário, mas este cenário só funciona se integrado com uma aplicação de terceiros específica, a qual você não tem total acesso.
O fato de você não ter acesso traz um dilema: ou você ignora a integração e roda o teste, inviabilizando a obtenção de resultados assertivos, ou não testa de modo algum.
Nenhuma das opções é realmente a escolha ideal, mesmo se você encarar aquele ditado "feito é melhor que perfeito". Afinal, é muito tênue a linha entre não trazer os resultados corretos e não testar.
O ideal seria existir algo que possibilitasse que os testes trouxessem os melhores resultados, mesmo sem acesso à tecnologia necessária. A boa notícia é que existe!
Estamos falando dos test doubles.
O que são Test Doubles
De acordo com Martin Fowler, test doubles é um conceito usado quando, para viabilizar a realização de testes, algum objeto em produção precisa ser substituído por outro.
Fazendo um paralelo simplista, eles são como dublês de atores em um filme: substituem aplicações reais durante a realização de um teste por simular sua aparência e comportamento. Isso traz menos complexidade ao teste, além de permitir verificar uma parte de um sistema sem ficar preso em todas as suas outras porções.
Talvez você não esteja familiarizado com o termo test double. É que, às vezes, eles são generalizados pela palavra mock, ou então pela expressão "mockar" . O fato é que mock é apenas um dos exemplos de test doubles dentro de uma família muito maior.
Além dos mocks, existem, por exemplo, os fakes, os stubs, os dummies… Abaixo, explico alguns deles.
São test doubles que têm implementações reais diferentes àquelas que existem em produção. Podemos considerá-los como um "atalho", algo implementado para deixar a execução do teste mais dinâmica frente ao que é colocado no ar de fato.
Basicamente, não há lógica em um fake — ele retorna um valor determinado por quem o implementa e, justamente por isso, não é um elemento adequado para ir à produção. Contudo, ele elimina a necessidade de implementar uma funcionalidade real, o que seria bem mais complexo.
Os mocks tem expectativas sobre o jeito que deve ser chamado e, caso ele não seja chamado da forma correta, o teste deve falhar.
Eles são usados para testar interações entre métodos e são úteis onde não há como verificar algumas mudanças de estado ou retornos do método testado diretamente.
Fonte: https://bit.ly/33NGlZY
Um spy age como um espião sob a implementação real e, como o mock, consegue verificar as interações entre os métodos.
A diferença para o mock é que o spy chama a implementação real para todos os métodos da interface mockada, a não ser que para algum método este seja configurado para retornar algo específico diferente da implementação real.
São similares aos fakes e aos spies, mas, ao contrário destes, ele consegue alterar seu comportamento com base na maneira como ele foi chamado no teste.
Isso permite que mais de um cenário para uma única dependência seja representado no teste.
Os dummies são dados que substituem dados reais, mas que não chegam a ser realmente utilizados no teste. São normalmente usados para satisfazer determinados parâmetros.
Como uso de dummies é possível diminuir a complexidade durante a escrita de um teste, ignorando o que não é relevante no cenário e focando no que realmente importa.
Existem diversos cenários nos quais a aplicação de test doubles podem viabilizar testes mais descomplicados e ainda assim assertivos. Um dos exemplos clássicos, citado por Martin Fowler, é quando vamos testar um processo que dispara um e-mail no final de sua cadeia.
O fato é que nem sempre é preciso realizar o envio desses e-mails durante a fase de testes. Então, podemos configurar um test double que vai simular o comportamento desejado, sem de fato enviar os e-mails.
Decidir qual test double mais adequado dependerá do seu objetivo. Se você quer apenas saber se o e-mail foi enviado, um stub seria o mais adequado. Caso o objetivo seja fazer uma validação de conteúdo, destinatário ou coisas mais complexas, talvez um mock seria a opção mais certeira.
Aqui na Sofist, já utilizamos test doubles em diversas situações. Em uma delas, precisavamos validar um cenário em um aplicativo que gerava uma requisição de compra na App Store. Como não era viável realizar uma compra a cada vez que realizássemos o teste, utilizamos um test double para emular essa requisição de pagamento e viabilizar o a validação sem complicações.
São exemplos simples, mas o uso de test double pode englobar desde as situações mais rotineiras até as mais complexas. O princípio é o mesmo: viabilizar com mais facilidade a realização de testes que dependem de outros fatores para acontecer.
Quer aprender mais sobre test double, suas aplicações e suas particularidades? Nosso time elaborou um material super completo sobre o assunto. Clique no botão abaixo e baixe o material!
A pressão por evoluções técnicas pode prejudicar... Previous
Lojas virtuais perdem, pelo menos, R$ 132,05 milhões... Next
Muito legal esse comparativo entre os vários Test Doubles! Normalmente só se apegam aos Mocks e esquecem dos vários possíveis métodos para cada caso. Uma boa aplicação desses conceitos seria nos Testes de Contrato, como também o próprio Martin Fowler comenta: https://martinfowler.com/bliki/ContractTest.html . Em um contexto de Microserviços, eu considero que Consumer-Driver Contracts com automação são excelentes para que um serviço apoie o outro: https://martinfowler.com/articles/consumerDrivenContracts.html
Excelente Lucas estamos usando o CDC com pact em um projeto. Voce ja aplicou o CDC em algum? Bora trocar experiencias!
Acredito que você inverteu a explicação de fakes e stubs. Stubs vão sempre responder com a resposta pré programada, independente da entrada feita para o método do mesmo. Já os fakes tem uma implementação que pode reagir conforme a entrada, ex: in-memory database. O artigo do Martin Fowler dá algumas explicações: https://martinfowler.com/bliki/TestDouble.html