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
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
Primeiro vamos criar o model Post e migrar ele.
rails g model Post titulo corpo:text
rails db:migrate
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
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
Bem, vamos rodar o teste.
rspec
.
Finished in 0.08076 seconds (files took 3.83 seconds to load)
1 example, 0 failures
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
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
É, 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
Agora, os testes devem passar.
rspec
.....
Finished in 0.08726 seconds (files took 4.24 seconds to load)
5 examples, 0 failures
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
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
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
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
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
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
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)