Testando Request em RSpec Rails
Tags: rails, rspec, testing
Published: 2022-12-09 10:08:58

Anteriormente, nós fizemos teste para model, agora vamos fazer teste para requests.

## O que é o request e porque é importante testar ele.

Antes de nós testar, primeiramente, nós temos que entender o request, que traduzindo seria, requisição.

Você deve saber, eu espero, que a nossa internet funciona com base de requisição e resposta, ou seja, no meu navegador, eu estou requisitando uma página web para um servidor, e o servidor, por sua vez, vai me dar uma resposta sobre a requisição. 

O servidor pode aceitar a requisição, pode negar ou até mesmo pode dar erro.

E é esse o nosso objetivo, nós queremos testar o que acontece quando faço requisição de formato HTML ou JSON, ou então quando acesso em uma página não autorizada, etc.

Então, para começar, vamos criar uma aplicação do começo para que vocês consigam me acompanhar.

A nossa ideia da aplicação é um simples blog, onde vai ter um controller e um model que é o post.

Se você quiser me acompanhar, basta executar os comandos abaixo para criar a aplicação.

```bash
rails new blog --skip-test
cd blog
echo 'gem "rspec-rails", group: [:development, :test]' >> Gemfile
echo 'gem "rails-controller-testing", group: :test' >> Gemfile
bundle install
rails g rspec:install
rails g resource Post titulo corpo:text
rails db:create db:migrate
```

Pronto com isso, estamos pronto para testar.

## Testando

Beleza, para testar os requests não é tão difícil assim.

vamos escrever os testes

```ruby
# spec/requests/posts_spec.rb
require 'rails_helper'

RSpec.describe "Posts", type: :request do
  describe "GET posts" do
    it "deve retornar sucesso" do
      get posts_path

      expect(response).to have_http_status(:success)
    end
  end

  describe "GET post" do
    it "deve retornar sucesso" do
      post = Post.create(titulo: "Ólá", corpo: "bla bla bala")
      get post_path(post)

      expect(response).to have_http_status(:success)
    end

    it "deve ser redirecionado por não existir o post" do
      get post_path("não existo")

      expect(response).to have_http_status(:not_found)
    end
  end

  describe "GET new post" do
    it "deve retornar sucesso" do
      get new_post_path

      expect(response).to have_http_status(:success)
    end
  end

  describe "Post posts" do
    it "deve retornar created" do
      post posts_path, params: {
        post: {
          titulo: "Reza a lenda",
          corpo: "Ele está vindo"
        }
      }

      expect(response).to redirect_to(post_path(assigns(:post)))
    end
  end

  describe "GET edit post" do
    it "deve retornar sucesso" do
      post = Post.create(titulo: "Ólá", corpo: "bla bla bala")
      get edit_post_path(post)

      expect(response).to have_http_status(:success)
    end

    it "deve ser redirecionado por não existir o post" do
      get edit_post_path("não existo")

      expect(response).to have_http_status(:not_found)
    end
  end

  describe "PUT post" do
    it "deve retornar sucesso" do
      post = Post.create(titulo: "Ólá", corpo: "bla bla bala")
      put post_path(post), params: {
        post: {
          titulo: "sou eu o",
          corpo: "tiririca"
        }
      }

      expect(response).to redirect_to(post_path(assigns(:post)))
    end

    it "deve ser redirecionado por não existir o post" do
      put post_path("não existo"), params: {
        post: {
          titulo: "sou eu o",
          corpo: "tiririca"
        }
      }

      expect(response).to have_http_status(:not_found)
    end
  end

  describe "DELETE post" do
    it "deve retornar sucesso" do
      post = Post.create(titulo: "Ólá", corpo: "bla bla bala")
      delete post_path(post)

      expect(response).to have_http_status(:redirect)
    end

    it "deve ser redirecionado por não existir o post" do
      delete post_path("não existo")

      expect(response).to have_http_status(:not_found)
    end
  end
end

```

É meio grandinho, mas não tem muitas diferenças em teste de model, como nós fizemos antes.

Só vamos dar a atenção nesses métodos que vou citar.

- `get`
- `post`
- `put`
- `delete`
- `have_http_status`
- `redirect_to`
- `assigns`

É só isso, porém existe mais métodos, como `patch` etc, mas raramente você usa ele.

Os primeiros quatros métodos são, obviamente, métodos de requisição HTTP, se não sabe sobre isso, eu recomendo que estude isso, porque isso é bastante importante.

Não tem muito o que explicar sobre eles, pois o próprio nome diz o que eles fazem.

Então vamos para `have_http_status` e `redirect_to`.

O `have_http_status` é um método para verificar se o argumento passado é equivalente ao "status code" da resposta do servidor.

Enquanto o `redirect_to` é o método para verificar se o argumento passado é equivalente ao página que o servidor redirecionou.

Não tem muito segredo, se você entende de protocolo HTTP.

Agora nós temos o método `assigns`, ele relaciona com a variável da instância, ou seja, vamos pegar o nosso caso, o argumento que eu passei foi `:post`, isso seria o equivalente o `@post`, isso é útil para caso em que você quer o id do post, que é o nosso caso, ou então saber que ele foi criado ou atualizado com sucesso.

Pronto, terminei com a explicação, agora vamos testar.

```bash
rspec

Finished in 0.4995 seconds (files took 4.57 seconds to load)
13 examples, 11 failures, 2 pending

Failed examples:

rspec ./spec/requests/posts_spec.rb:5 # Posts GET posts deve retornar sucesso
rspec ./spec/requests/posts_spec.rb:13 # Posts GET post deve retornar sucesso
rspec ./spec/requests/posts_spec.rb:20 # Posts GET post deve ser redirecionado por não existir o post
rspec ./spec/requests/posts_spec.rb:28 # Posts GET new post deve retornar sucesso
rspec ./spec/requests/posts_spec.rb:36 # Posts Post posts deve retornar created
rspec ./spec/requests/posts_spec.rb:49 # Posts GET edit post deve retornar sucesso
rspec ./spec/requests/posts_spec.rb:56 # Posts GET edit post deve ser redirecionado por não existir o post
rspec ./spec/requests/posts_spec.rb:64 # Posts PUT post deve retornar sucesso
rspec ./spec/requests/posts_spec.rb:76 # Posts PUT post deve ser redirecionado por não existir o post
rspec ./spec/requests/posts_spec.rb:89 # Posts DELETE post deve retornar sucesso
rspec ./spec/requests/posts_spec.rb:96 # Posts DELETE post deve ser redirecionado por não existir o post
```

Bem, nós esquecemos de criar as actions do controller e as  views.

Vamos para `app/controller/posts_controller.rb` e criar as actions.

```ruby
# app/controller/posts_controller.rb

class PostsController < ApplicationController
	before_action :define_post, except: [:index, :new, :create]

	def index
          @post = Post.all
	end

	def show
	end

	def new
	end

	def create
		@post = Post.new 

		if @post.save
			redirect_to post_path(@post)
		else
			render :new, status: :unprocessable_entity
		end
	end

	def edit
	end

	def update
		if @post.update post_params
			redirect_to post_path(@post)
		else
			render :edit
		end
	end

	def destroy
		if @post.destroy
			redirect_to posts_path
		end
	end

	private

	def post_params
		params.require(:post).permit(:titulo, :corpo)
	end

	def define_post
		begin
			@post = Post.find(params[:id])
		rescue ActiveRecord::RecordNotFound
			redirect_to posts_path, status: :not_found
		end
	end
end
```

Pronto, criamos as actions, agora vamos criar as views, basta executar os comandos abaixo.

```bash
touch app/views/posts/index.html.erb app/views/posts/show.html.erb app/views/posts/new.html.erb app/views/posts/edit.html.erb
```

Agora sim, nós estamos pronto, vamos rodar o teste.

```bash
rspec

Finished in 0.81536 seconds (files took 4.77 seconds to load)
13 examples, 0 failures, 2 pending
```

Passou.

E é isso, terminamos aqui, só que não, eu estava pensando aqui, será que vale a pena fazer um teste para uma aplicação de API? Pois é útil aprender como que testa as requisições do tipo JSON.

Mas não vale a pena, porque seria um copiar e colar e colocar um argumento header e testar se resposta é json.

Eu só vou fazer só um teste de requisição para ter noção.

Vamos para `spec/requests/post_spec.rb`.

```ruby
# spec/requests/post_spec.rb
require 'rails_helper'

RSpec.describe "Posts", type: :request do
  describe "GET posts" do
    ...

    describe "requisição json" do
      it "deve retornar sucesso" do
        headers = { "ACCEPT": "application/json" }
        get posts_path, headers: headers

        expect(response.content_type).to eq("application/json; charset=utf-8")
        expect(response).to have_http_status(:success)
      end
    end
  end
  ...
end
```

Se nós analisamos o teste, vai perceber que não teve muita diferença o que a gente fez anteriormente, eu passei o argumento `headers` no `get` e testei se o tipo de conteúdo é JSON, só isso.

Se nós rodar o teste, é obvio que vai falhar, então para evitar isso, vamos para `app/controller/post_controller.rb`.

```ruby
class PostsController < ApplicationController
  ...
  def index
    @posts = Post.all

    respond_to do |format|
      format.html
      format.json { render json: @posts }
    end
  end
  ...
end
```

Com isso, a nossa aplicação aceita a requisição HTML e JSON.

Agora, se nós rodar o teste, vai funcionar, e isso é o suficiente para nós testar a aplicação que atende requisição json.

Com isso, nós terminamos aqui.

Tchau!