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)