DEV Community

Alexandre
Alexandre

Posted on • Edited 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)