Testando Controllers com Rspec

Irei abordar aqui um pouco sobre rspec e testes com controllers.
 Quando estamos começando a aprender alguma linguagem de programação nova ou algum framework, muitas dúvidas surgem e, muitas vezes, não conseguimos encontrar uma solução ideal para o nosso problema. O que fazemos, normalmente, é pesquisar em diversos lugares e ir juntando pedaços de informação em cada site, entrevista, livro e blog. Outro grande problema é que ao cair de cabeça em uma nova linguagem, mesmo com a ajuda de livros, muitas dúvidas surgem e, por não termos conhecimento de comunidades, sites, blogs e todo o ecossistema desta nova linguagem, fica difícil conseguir tirar dúvidas que às vezes parecem simples, a coisa complica mais ainda quando temos dúvidas que vão além de uma sintaxe, como por exemplo uma dúvida estrutural, como organizar melhor um projeto, melhores arquiteturas, e se eu precisar fazer algo que saia do padrão, como vou fazer? Essas dúvidas são pertinentes e muitas vezes são difíceis de serem explicadas em blogs ou posts em comunidades de software. Um dos aspectos que percebo que quebram a cabeça de muita gente diz respeito à testes de controllers em Rails. Há muito debate sobre o assunto e, enquanto alguns preferem não testar os controllers deixando para testes de integração a responsabilidade de provar que tudo está certo, outros preferem testar os controllers detalhadamente. Ainda existe a vertente que prefere testar controllers sem mocks e aqueles que preferem testar com mocks. A discussão é antiga e ainda hoje se mantém. Na Roga Labs, empresa onde trabalho, temos como prioridade fazer sistemas com um alto padrão de qualidade e uma das formas que aprendemos a muito tempo para mantermos uma boa qualidade do software que produzimos é trabalhar com TDD. Particularmente eu sou um apoiador e disseminador da metodologia de test first a um bom tempo, tendo formado equipes e dado palestras sobre o tema eu entendo e percebo a dificuldade de muitas pessoas com relação à testes de software.

Como sempre digo, tudo se resume na fundação. Um bom desenvolvedor de software não estuda só frameworks, nem muito menos sintaxes básicas de uma linguagem, ele vai além. A teoria é igual para todo mundo, ter uma excelente base de lógica de programação é o primeiro passo, mas não é só isso, é necessário aprender metodologias, técnicas para construção de software, ir mais a fundo nas linguagens que deseja aprender.

Além da experiência adquirida com os anos existem excelentes livros que te ajudam a hackear alguns anos e, talvez, ficar à frente da concorrência. Com relação à testes de software dois me vem a mente, um deles é como uma bíblia e deve andar sempre debaixo do braço: xUnit Patterns. O outro seria mais como uma boa introdução ao tema TDD: Test-Driven Development. Esses dois livros não foram feitos para uma linguagem específica ou para um projeto específico, são livros que transcendem as barreiras de linguagem e frameworks. Bons livros de software não são específicos à um grupo de developers e mais uma vez é importante lembrar o porque de livros como esses serem importantes: eles são a fundação. É lógico que existem outros, mas muitas dúvidas relacionadas à testes de software são explicadas nesses livros. É fácil enxergar muitos padrões adotados em frameworks de testes ao ler o livro do xUnit (aconselho não ler o livro inteiro já que é muito grande e é um livro de padrões, é importante ler todo só a primeira parte). É importante ressaltar que não há nada de novo debaixo do sol, todos os padrões e metodologias que vemos surgir nos últimos anos são reformulações e adaptações de metodologias já existentes. Não se deixem iludir por nenhum novo framework ou linguagem, todos tem suas qualidades e seus defeitos e servem para propósitos específicos. Não existe uma bala de prata nem um framework para tudo e para todos. Eu prefiro ter uma fundação sólida do que saber dez frameworks da moda.

Nesse post irei me concentrar em testes de controller. É importante que testes unitários não sejam dependentes da existência de outros objetos com suas particularidades e implementações, principalmente, quando vamos testar camadas que não acessam dados ou outros sistemas, devemos tentar manter o teste o mais unitário possível ou seja, independente do comportamento de outros objetos e classes do sistema. Para isso nós utilizamos mocks(Gerard Meszaros — Test Doubles) e verificamos o comportamento do nosso SUT(System under test) através de expectativas nos objetos mockados. Isso nos dá duas vantagens: a primeira é que não mais acessamos o banco de dados. E a segunda é que não precisamos implementar de verdade o objeto mocado já que ele é um dublê.

Outra característica é que mesmo usando shared exemples e shared contextos seu arquivo *_spec.rb pode ficar muito grande. É uma opinião pessoal, mas odeio arquivos grandes, por isso dividimos os testes por ações e, embora essa forma de agir possa gerar algumas duplicações nos testes, nos sentimos melhor pelo fato de que, agora, os arquivos de testes são bem menores e mais fáceis de serem lidos. Ainda não atingimos nem de perto o ponto que queremos chegar, mas acreditamos que estamos no começo.

Neste exemplo vou mostrar um caso crud. Não é necessário entender o modelo de negócio envolvido, não fará muita diferença.

Algumas partes podem e devem ser refatoradas para métodos auxiliares e até classes de ajuda, mas resolvi deixar assim para melhorar a legibilidade do código neste post e para que pessoas que estão iniciando agora consigam entender melhor a leitura de cima para baixo.

Basicamente todos os testes se utilizam da gem factory_girl para gerar os objetos. A classe Residence é um active record mas se notarem não o banco de dados não é chamado pois utilizamos double e build_stubbed para criar os objetos de forma fake. No arquivo de testes da action #create são três testes importantes, se os parâmetros permitidos são os que esperamos, se há um redirecionamento para onde esperamos e se o objeto é criado com sucesso. Também testamos no caso de atributos inválidos, não nos preocupamos muito em testar todos os atributos inválidos pois os testes de model já fazem isso por nós, aqui nos preocupamos apenas em verificar se o comportamento do controller é o esperado quando passamos um objeto com algum parâmetro inválido.

Neste mesmo arquivo é possível verificar dois shared examples chamados redirectable action e renderable action que testam o redirecionamento e a renderização correta respectivamente. Há também um shared context que testa se há o redirecionamento para a tela de login caso o usuário não esteja logado.

Todos os códigos seguem abaixo. Adoraria sugestões para melhorias.

Até a próxima.

Index Residence Spec

Show Residence Spec

New Residence Spec

Edit Residence Spec

Create Residence Spec

Update Residence Spec

Destroy Residence Spec

Shared Examples

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.