Teste de unidade usando Mock e Stub na prática

Mateus Leonardi
We are HeroSpark
Published in
4 min readMay 21, 2021

--

Hoje, quero falar um pouco sobre uma parte muito importante do teste unitário: Mock & Stub na prática!

Isso porque uma das nossas dores na HeroSpark era que com o passar do tempo manter testes integrados que acessam o banco e outros recursos pode se tornar algo complexo e, com isso, o aumento do custo com manutenção é inevitável.

Sem contar que o tempo do processo de entrega das alterações acaba se prolongando muito conforme a aplicação cresce, pois são adicionados mais testes que dependem do banco de dados para funcionar corretamente.

Portanto, ao organizar a arquitetura da aplicação e aplicar os conceitos de Mock & Stub, podemos escrever nossos testes de unidade de fato e, com isso, mantê-los rodando de forma rápida, como deve ser.

Beleza, mas o que é Mock e Stub?

O Mock é um trecho de código fictício que você VERIFICA, é chamado de fato como parte do teste. Para exemplificar, significa que você confere se algum método foi chamado ou se uma determinada propriedade está com o valor esperado ou se o retorno de algum método está de acordo com o esperado.

Já o Stub é um pedaço de código fictício que simula o comportamento de algo, mas você não se importa com o que acontece com ele. Já que você só quer o resultado gerado para facilitar algum passo do seu teste.

Uma relação confusa, vamos tentar simplificar…

O Mock é usado para verificar se um componente foi chamado durante a execução ou se o retorno dele está dentro do esperado pelos cenários propostos nos testes.

Enquanto isso, Stub é quando você simula o comportamento de algo para encurtar o teste e não se interessa pelo o que acontece naquele código, você só quer o retorno ou que ele execute o método.

Espero que tenha ajudado a esclarecer um pouco mais.

Como fazemos o teste unitário na prática em Ruby on Rails na HeroSpark?

Importante: Em todos os exemplos abaixo foi utilizado o RSpec.

Vou colocar exemplos baseados em operações do ActiveRecord por acreditar que são cenários quase rotineiros em projetos RoR (Ruby on Rails).

Para isso, vou criar essas variáveis auxiliares no início da nossa classe de teste e reusar nos exemplos de Mocks e Stubs.

No exemplo abaixo com o “before”, estou dizendo ao código o que ele deve retornar quando chamarmos o “User.create”. Isso evita que o código durante o teste acesse o banco de dados, deixando ele mais rápido. Assim, você não precisa testar o ORM*.

Nesse próximo exemplo, vou fazer algo similar, porém dessa vez fazendo um Stub para o método “where”.

Você pode aplicar essa mesma técnica e fazer Stub em qualquer código que acesse um serviço/recurso, trazendo maior velocidade para os seus testes unitários e também maior controle para que você possa testar quaisquer cenários que queira sem grandes dificuldades.

Por exemplo, caso você estruture um pouco seu código, também consegue fazer Stubs de métodos que façam uma request web, tornando mais simples e menos verboso seu teste unitário.

Quando aplicamos esses conceitos, de fato escrevemos testes que sejam unitários e temos diversos ganhos. Dentre eles posso destacar: maior rapidez e maior liberdade de explorar cenários. Assim, ganhamos em manutenabilidade, pois evoluímos a organização do nosso código e a arquitetura.

Quando digo maior rapidez também significa que pode acontecer até uma redução de custos dependendo da forma como o CI/CD** acontece no seu projeto, além de ganhar mais agilidade nessa etapa. Assim como ajuda os devs a terem um feedback mais rápido se a sua alteração impactou negativamente algo no projeto, tornando o processo de desenvolvimento mais rápido e fluido com o passar do tempo.

É importante mencionar que o começo pode ser bem doloroso e talvez até desmotivador, pois será um pouco mais lento até que seja adquirido conhecimento e esteja documentado através dos testes, formando assim uma base de conhecimento adequada. Porém, a qualidade, a segurança e a velocidade para execução dos testes e demais benefícios fazem valer o investimento.

Podemos concluir que os projetos são maratonas e que testes unitários estão sempre visando o médio/longo prazo do projeto tanto em qualidade quanto em custo para desenvolver e manter não só a aplicação, mas também os testes. Não é sobre correr muito hoje, é sobre manter um ritmo que possibilite seguir nele e atingir os resultados e objetivos com qualidade e segurança.

*ORM: Object-relational Mapping (Mapeamento de objeto-relacional) é uma técnica de desenvolvimento utilizada para reduzir a impedância da programação orientada a objetos. ActiveRecord é uma implementação desse conceito.

**CI/CD: Em engenharia de software, CI/CD ou CICD pode se referir às práticas combinadas de integração contínua e entrega contínua. Jenkins, Github Actions, por exemplo, são ferramentas utilizadas para fazermos uso desse conceito.

Bônus!

Se você quiser ver o código completo do teste utilizado, assim como as referências adicionadas no topo da classe de teste “user_spec.rb”, acesse o conteúdo recomendado.

--

--