[PT-BR] - RSPEC & RUBY - DO GO HORSE AO TDD
Tags: ruby, rails, tdd, testing
Published: 2022-01-15 20:09:52

# **Prólogo**

O que você irá ler abaixo são apenas alguns dos vários motivos para se usar testes, especialmente desenvolver guiado por testes.

Como um desenvolvedor iniciante, sempre questionei internamente os porquês dos testes, mesmo com todos ao meu redor dizendo sua importância e valor, nunca havia posto em prática as técnicas necessárias para executar bons testes e/ou desenvolver algo totalmente guiado por eles, antes a vida era bem simples, era só montar no cavalo e escrever tudo às cegas, sem planejamento, sem pensar, o belo **e não ideal** eXtreme Go Horse. No entanto, com isso me vi perdendo produtividade, testar tudo de um código "na unha" se tornou cansativo demais, brechas e bugs apareciam com facilidade, foi nesse momento em que me dei conta, com a seguinte frase passando pela minha cabeça: "Se eu tivesse os testes escritos, tudo seria mais tranquilo". Dessa forma, com esse pensamento, tomei vergonha na cara e entrei a fundo naquilo que chamam de Test Driven Development, ou melhor, TDD.

## **Sobre o TDD:**

Test Driven Development, ou comumente conhecido como TDD, é uma técnica de desenvolvimento em que o desenvolvedor primeiro pensa nas funções e/ou comportamentos do seu código, escreve os testes para só posteriormente escrever as linhas de código propriamente ditas. Sua importância se dá pela previsibilidade das funções definidas pelo teste, em que você arquiteta todo o código sabendo exatamente o que deve(ria) ser retornado. Desse modo, o TDD é formado pelos seguintes passos:

1. **(RED)** Escrever um teste que falhe: Ao escrever o teste, ele obviamente irá falhar a priori, pois você não tem código nenhum para fazer o que o teste espera que seja feito.

2. **(GREEN)** Fazer o código funcionar: Ao escrever o código, o desenvolvedor deve fazer o possível para que o teste seja aceito, não importando como.

3. **(REFACTOR)** Eliminar a redundância: Após garantir o funcionamento do código, o desenvolvedor deverá aplicar ao máximo as boas práticas da linguagem, buscando sempre o equilíbrio entre legibilidade e qualidade.

## **Conhecendo o RSpec:**

Não vou entrar a fundo na instalação e afins pois esse não é o foco da postagem, mas [aqui](https://github.com/rspec/rspec-rails) e [aqui](https://rspec.info/) você encontrará tudo o que é preciso para entender e utilizar o RSpec com Ruby e Rails.

O **RSpec** é uma ferramenta (*gem*) de testes para códigos na linguagem **Ruby**, sendo uma das mais famosas e geralmente acompanhado de outras **gems** que amplificam sua utilidade, tais como: *Capybara*, *Cocumber* e *Factorybot* (antigo FactoryGirl).

Sua sintaxe simples e muito semelhante com a lingua inglesa auxília no entendimento e escrita de testes, geralmente com suas descrições feitas na terceira pessoa.

```ruby
RSpec.describe ArticlesController do
  describe '#index' do
    it 'returns a success response' do
      get '/articles'
      expect(response).to have_http_status(:ok)
    end
    
    it 'returns articles in a proper order' do
      older_article = 
        create(:article, created_at: 1.hour.ago)
      recent_article = create(:article)
      get '/articles'
      ids = json_data.map { |item| item[:id].to_i }
      expect(ids).to(
        eq([recent_article.id, older_article.id])
      )
    end
  end
end
```
### **Entendendo o código:**

* ***.describe:*** Utiliza-se *describe* para descrever as *classes*, *módulos* ou *métodos* em que irão ser feitos os testes. Nesse caso o que está sendo descrito acima é a classe ***ArticlesController.*** e a chamada ***index*** da rota ***/articles***.

* ***it:*** Utiliza-se *it* para descrever o que será testado (descrito na terceira pessoa). Nesse caso *'Returns a success response'* implica na requisição de ***get '/articles'*** retornar uma resposta "Sucesso", ou melhor, o **status HTTP 200 (OK)**.

O próximo passo, sob o viés do TDD, você deverá rodar o comando `rspec` no seu terminal para iniciar o teste, que obviamente falhará, na maioria dos casos, a falha do teste te dará um norte sobre o que deve ser feito.

Após isso, será iniciada a linha de pensamento para o código ser aceito pelo teste, nesse caso:

> Exemplo do teste feito em uma API.

* **Deverá existir um _Model_ e um _Controller_ para articles, juntamente com um Serializer (JSON API gem) para definir os atributos e organizá-los e um método index para renderizar o arquivo em formato .json**.

  ```ruby
  #./app/models/article.rb

  class Article < ApplicationRecord
    validates :title, presence: true
    validates :content, presence: true
    validates :slug, presence: true, uniqueness: true

    scope :recent, -> { order(created_at: :desc) }
  end

  # ./app/controllers/articles_controller.rb

  class ArticlesController < ApplicationController
    def index
      articles = Article.recent
      render json: serializer.new(articles), status: :ok
    end
    
    def serializer
      ArticleSerializer
    end
  end

  # ./serializers/article_serializer.rb

  class ArticleSerializer
    include JSONAPI::Serializer
    attributes :title, :content, :slug
  end

  ```

* **O código deverá ter uma rota definida para o controller articles juntamente com o método index.**

    ```ruby
    # ./config/routes.rb
   Rails.application.routes.draw do
     resources :articles, only: %i[index]
   end

    ```
Fazendo isso e rodando novamente `rspec` é esperado que o teste passe.

# Conclusão

Seguindo dois dos três passos do TDD, consegue-se chegar a um código que terá sempre testes que podem indicar seu funcionamento digitando um simples comando no terminal, o que por sua vez é muito útil caso o desenvolvedor queira seguir o terceiro passo do TDD e refatorar, melhorar e adicionar novas funcionalidades para sua aplicação / API. 

Sob essa ótica, o aumento da produtividade e qualidade de código será apenas questão de tempo, conforme o desenvolvedor aprende mais de suas ferramentas de teste, suas nuances e novas técnicas.