DEV Community 👩‍💻👨‍💻

Alexandre
Alexandre

Posted on • Updated on

Testando model em RSpec Rails.

Vamos aprender a testar o model em rails usando o RSpec.

Mas antes de aprender a testar, vamos criar uma aplicação para ter uma visualização a nossa aplicação.

Eu vou criar um simples blog, em que vai ter duas tabelas.

Post: titulo e corpo
Comentario: texto e post_id
Enter fullscreen mode Exit fullscreen mode

Tendo a noção da minha aplicação, vamos criar ele.

Criando a aplicação

rails new testando_model --skip-test
cd testando_model
rails db:create db:migrate
echo 'gem "rspec-rails", group: [:development, :test]' >> Gemfile
bundle install
rails g rspec:install
Enter fullscreen mode Exit fullscreen mode

Primeiro vamos criar o model Post e migrar ele.

rails g model Post titulo corpo:text
rails db:migrate
Enter fullscreen mode Exit fullscreen mode

Pronto com isso, nós podemos testar.

Testando o model

Vamos abrir o arquivo spec/models/post_spec.rb e fazer um teste simples.

Então vamos fazer um teste simples.

# spec/models/post_spec.rb
require 'rails_helper'

RSpec.describe Post, type: :model do
  it "deve criar um post" do
    Post.create
    expect(Post.count).to equal(1)
    # traduzindo isso, seria desse jeito
    # Espero que a contagem do post seja igual 1
  end
end
Enter fullscreen mode Exit fullscreen mode

O método it permite você passe o argumento de uma string que explique o seu teste e tem que utilizar o bloco para executar o seu teste.

O método expect recebe o argumento do valor atual, que o nosso caso é a contagem do post, e depois disso, tem o to que tenta comparar o valor atual de acordo com primeiro argumento, que é o método equal que contém o valor esperado.

Isso seria a mesma lógica que esse código que eu vou fazer, só que o meu código não foi feito para teste.

Post.count == 1
Enter fullscreen mode Exit fullscreen mode

Bem, vamos rodar o teste.

rspec
.

Finished in 0.08076 seconds (files took 3.83 seconds to load)
1 example, 0 failures
Enter fullscreen mode Exit fullscreen mode

O teste passou, isso significa que pelos menos é possível criar um post.

Agora vamos nos aprofundar um pouco.

Eu quero testar que não é possível criar um post sem título e corpo.

Também quero que tenha limite de caracteres do título e do corpo.

Então eu vou mudar o primeiro teste para que possa adaptar as condições que citei em cima e adiciona mais testes.

# spec/models/post_spec.rb
require 'rails_helper'

RSpec.describe Post, type: :model do
  it "deve ser valido um post com titulo e corpo" do
    post = Post.new(
      titulo: "Instalando rpsec",
      corpo: "Lero lero"
    )
    expect(post).to be_valid
    # espero que o post seja valido
  end

  it "não deve ser valido sem o titulo" do
    post = Post.new(
      titulo: nil,
      corpo: "Lero lero"
    )
    expect(post).not_to be_valid
    # espero que o post não seja valido
  end

  it "não deve ser valido sem um titulo" do
    post = Post.new(
      titulo: "instalando rpsec",
      corpo: nil
    )
    expect(post).not_to be_valid
    # espero que o post não seja valido
  end

  it "não deve ser valido com um titulo maior que 50 caracteres" do
    post = Post.new(
      titulo: "a"*51,
      corpo: nil
    )
    expect(post).not_to be_valid
    # espero que o post não seja valido
  end

  it "não deve ser valido com um corpo maior que 500 caracteres" do
    post = Post.new(
      titulo: "Como não ser burro",
      corpo: "o"*501
    )
    expect(post).not_to be_valid
    # espero que o post não seja valido
  end
end
Enter fullscreen mode Exit fullscreen mode

Pronto, Vamos rodar o teste.

rspec

Finished in 0.15579 seconds (files took 4.44 seconds to load)
5 examples, 4 failures

Failed examples:

rspec ./spec/models/post_spec.rb:13 # Post não deve ser valido sem o titulo
rspec ./spec/models/post_spec.rb:22 # Post não deve ser valido sem um titulo
rspec ./spec/models/post_spec.rb:31 # Post não deve ser valido com um titulo maior que 50 caracteres
rspec ./spec/models/post_spec.rb:38 # Post não deve ser valido com um corpo maior que 500 caracteres
Enter fullscreen mode Exit fullscreen mode

É, os testes falharam, isso significa que nossa aplicação não está seguindo do jeito que nós queríamos.

Então, vamos consertar a nossa aplicação.

Primeiro, vamos para o arquivo app/models/post.rb e adicionar algumas validação.

# app/models/post.rb
class Post < ApplicationRecord
  validates :titulo, presence: true, length: { maximum: 50 }
  validates :corpo, presence: true, length: { maximum: 500 } 
end
Enter fullscreen mode Exit fullscreen mode

Agora, os testes devem passar.

rspec

.....

Finished in 0.08726 seconds (files took 4.24 seconds to load)
5 examples, 0 failures
Enter fullscreen mode Exit fullscreen mode

Ta dã, os testes passaram, isso significa que no minimo, o seu código é minimamente confiável.

Mas vamos organizar ele, pois está feio.

# spec/models/post_spec.rb
require 'rails_helper'

RSpec.describe Post, type: :model do
  subject(:post) do
    Post.new( titulo: "Instalando rpsec", corpo: "Lero lero" )
  end

  context "é valido" do
    it "deve ser valido um post com titulo e corpo" do
      expect(post).to be_valid
    end
  end

  context "não está preenchido os campos" do
    it "não deve ser valido sem o titulo" do
      post.titulo = nil
      expect(post).not_to be_valid
    end

    it "não deve ser valido sem um titulo" do
      post.corpo = nil
      expect(post).not_to be_valid
    end
  end

  context "passou do limite de caracteres" do
    it "não deve ser valido com um titulo maior que 50 caracteres" do
      post.titulo = "a" * 51
      expect(post).not_to be_valid  end

    it "não deve ser valido com um corpo maior que 500 caracteres" do
      post.corpo = "o" * 501
      expect(post).not_to be_valid
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Você pode notar algumas palavras novas nesse código, mas não se preocupa que eu vou explicar cada uma dela.

Explicando o subject e context

Primeiro, vamos começar com subject, nós podemos dizer que é o objeto que está sendo testado, que o nosso caso seria o objeto da classe Post.

Com isso, nós podemos usá-la em qualquer parte do código.

Agora vamos falar sobre o context, como o nome diz, é o contexto do bloco.

No primeiro context, eu defino que aquele bloco, só tem validação correta.

Enquanto o segundo context foi definido que aquele bloco só tem validação incorreta por falta de valores.

E o terceiro, a mesma coisa que segundo, porém com ultrapassagem do limite de caracteres.

E é só isso.

Agora vamos testar o código

rspec

.....

Finished in 0.07729 seconds (files took 3.84 seconds to load)
5 examples, 0 failures
Enter fullscreen mode Exit fullscreen mode

Está funcionando.

Vamos tentar adicionar um teste que vai falhar com certeza absoluta.

Eu quero testar se o post tem comentário e quantos ele tem.

Eu vou omitir os outros testes para ocupar menos espaços.

# spec/models/post_spec.rb
...
  context "#tem_quantos_comentario" do
    it "deve ter dois comentario" do
      Comentario.create(texto: "Foda", post: post)
      Comentario.create(texto: "Gostei", post: post)

      expect(post.tem_quantos_comentario).to equal(2)
    end

    it "não deve ter nenhum comentario" do
      expect(post.tem_quantos_comentario).to equal(0)
    end
  end

  context "#tem_comentario?" do
    it "deve retornar true" do
      Comentario.create(texto: "Foda", post: post)

      expect(post.tem_comentario?).to be_truthy
    end

    it "deve retornar false" do
      expect(post.tem_comentario?).to be_falsey
    end
  end
Enter fullscreen mode Exit fullscreen mode

Vcoê pode ter percebido esse # antes do nome no context.

Isso é um forma de dizer que esse contexto está testando o método da instância. Se você colocar um . antes do método, você está dizendo que o contexto é testar o método da classe.

Se nós rodar o código, obviamente vai falhar, porque ainda não existe o model Comentario e os métodos, então vamos criar eles.

rails g model Comentario texto post:references
rails db:migrate
Enter fullscreen mode Exit fullscreen mode

Agora vamos criar os métodos e colocar associação do comentário com post.

# app/models/post.rb

class Post < ApplicationRecord
  has_many :comentarios

  validates :titulo, presence: true, length: { maximum: 50 }
  validates :corpo, presence: true, length: { maximum: 500 } 

  def tem_quantos_comentario
    self.comentarios.count
  end

  def tem_comentario?
    self.comentarios.count >= 1
  end
end
Enter fullscreen mode Exit fullscreen mode

Agora vamos testar o código.

rspec

*.........

Pending: (Failures listed here are expected and do not affect your suite's status)

  1) Comentario add some examples to (or delete) /tmp/testando_model/spec/models/comentario_spec.rb
     # Not yet implemented
     # ./spec/models/comentario_spec.rb:4


Finished in 0.19358 seconds (files took 3.74 seconds to load)
10 examples, 0 failures, 1 pending
Enter fullscreen mode Exit fullscreen mode

Está tudo funcionando.

Bem, eu não vou testar o comentário, porque não seria muito diferente do teste Post.

Então eu deixo você fazer o resto.

Pronto, com isso, nós podemos dar a segurança aos nossos models com esses testes.

É claro que os nossos testes feito aqui não o suficiente.

Nós temos que testar a associação, remoção de dados de banco de dados etc.

No próximo post, eu vou testar os requests.

E é isso, Tchau!

Top comments (0)

Build Anything...


Use any Linode offering to create something for the DEV x Linode Hackathon 2022. A variety of prizes are up for grabs, inculding $1,000 USD. 👀

Join the Hackathon <-