SlideShare uma empresa Scribd logo
1 de 107
Baixar para ler offline
RSpec Best Friends
Mauro quem...
maurogeorge.com.br
RSpec
sintaxe de expectativa
RSpec
spec/models/pokemon_spec.rb
it 'exibe o nome e o id nacional' do
pokemon = Pokemon.new(nome: 'Charizard', id_nacional: 6)
pokemon.nome_completo.should eq('Charizard - 6')
end
spec/models/pokemon_spec.rb
it 'exibe o nome e o id nacional' do
pokemon = Pokemon.new(nome: 'Charizard', id_nacional: 6)
expect(pokemon.nome_completo).to eq('Charizard - 6')
end
spec/models/pokemon_spec.rb
it { expect(subject).to be_a(ActiveRecord::Base) }
spec/models/pokemon_spec.rb
it { should be_a(ActiveRecord::Base) }
spec/models/pokemon_spec.rb
it { is_expected.to be_a(ActiveRecord::Base) }
Somente RSpec 3
spec/spec_helper.rb
RSpec.configure do |config|
# ...
config.expect_with :rspec do |c|
c.syntax = :expect
end
end
descrevendo melhor os testes
RSpec
spec/models/pokemon_spec.rb
it 'exibe o nome e o id nacional' do
pokemon = Pokemon.new(nome: 'Charizard', id_nacional: 6)
expect(pokemon.nome_completo).to eq('Charizard - 6')
end
spec/models/pokemon_spec.rb
describe '#nome_completo' do
it 'exibe o nome e o id nacional' do
pokemon = Pokemon.new(nome: 'Charizard', id_nacional: 6)
expect(pokemon.nome_completo).to eq('Charizard - 6')
end
end
não teste apenas o happy path
RSpec
spec/models/pokemon_spec.rb
describe '#nome_completo' do
it 'exibe o nome e o id nacional' do
pokemon = Pokemon.new(nome: 'Charizard', id_nacional: 6)
expect(pokemon.nome_completo).to eq('Charizard - 6')
end
end
spec/models/pokemon_spec.rb
describe '#nome_completo' do
it 'exibe o nome e o id nacional quando possui os valores' do
pokemon = Pokemon.new(nome: 'Charizard', id_nacional: 6)
expect(pokemon.nome_completo).to eq('Charizard - 6')
end
it 'é nil quando não possui o nome e o id nacional' do
pokemon = Pokemon.new
expect(pokemon.nome_completo).to be_nil
end
end
contextos para a melhor descrição
RSpec
spec/models/pokemon_spec.rb
describe '#nome_completo' do
context 'quando possui nome e o id nacional' do
it 'exibe o nome e o id nacional' do
# ...
end
end
context 'quando não possui o nome e o id nacional' do
it 'é nil' do
# ...
end
end
end
de!nindo o sujeito
RSpec
spec/models/pokemon_spec.rb
context 'quando possui nome e o id nacional' do
before do
@pokemon = Pokemon.new(nome: 'Charizard', id_nacional: 6)
end
it 'exibe o nome e o id nacional' do
expect(@pokemon.nome_completo).to eq('Charizard - 6')
end
end
spec/models/pokemon_spec.rb
context 'quando possui nome e o id nacional' do
let(:pokemon) do
Pokemon.new(nome: 'Charizard', id_nacional: 6)
end
it 'exibe o nome e o id nacional' do
expect(pokemon.nome_completo).to eq('Charizard - 6')
end
end
spec/models/pokemon_spec.rb
context 'quando possui nome e o id nacional' do
subject do
Pokemon.new(nome: 'Charizard', id_nacional: 6)
end
it 'exibe o nome e o id nacional' do
expect(subject.nome_completo).to eq('Charizard - 6')
end
end
utilize sempre os matchers
RSpec
spec/models/pokemon_spec.rb
it 'é nil' do
expect(subject.nome_completo).to eq(nil)
end
spec/models/pokemon_spec.rb
it 'é nil' do
expect(subject.nome_completo).to be_nil
end
não use should
RSpec
spec/models/pokemon_spec.rb
it 'should have the name and the national_id' do
expect(pokemon.full_name).to eq('Charizard - 6')
end
spec/models/pokemon_spec.rb
it 'does have the name and the national_id' do
expect(pokemon.full_name).to eq('Charizard - 6')
end
ordem aleatória nos testes
RSpec
spec/spec_helper.rb
RSpec.configure do |config|
# ...
config.order = "random"
end
https://github.com/mongoid/mongoid
https://github.com/bbatsov/ruby-style-guide
https://github.com/bbatsov/rails-style-guide
coding style
RSpec
Testes que acessam rede
Testes lentos
Testes quebradiços
Não poder testar sem rede
introdução
Testes que acessam rede
app/services/criador_pokemon.rb
class CriadorPokemon
# ...
def criar
Pokemon.create(nome: nome)
end
private
# ...
def cria_info
resposta = Net::HTTP.get(endpoint)
@info = JSON.parse(resposta)
end
end
spec/services/criador_pokemon_spec.rb
describe 'pokemon criado' do
before do
criador_pokemon.criar
end
subject do
Pokemon.last
end
it 'possui o nome correto' do
expect(subject.nome).to eq('Charizard')
end
end
webmock
Testes que acessam rede
webmock: feedback rápido
Testes que acessam rede
bash
Failure/Error: CriadorPokemon.new(6)
WebMock::NetConnectNotAllowedError:
Real HTTP connections are disabled. Unregistered request: GET http://
pokeapi.co/api/v1/pokemon/6/ with headers {'Accept'=>'*/*', 'Accept-
Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Host'=>'pokeapi.co', 'User-
Agent'=>'Ruby'}
You can stub this request with the following snippet:
stub_request(:get, "http://pokeapi.co/api/v1/pokemon/6/").
with(:headers => {'Accept'=>'*/*', 'Accept-
Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Host'=>'pokeapi.co', 'User-
Agent'=>'Ruby'}).to_return(:status => 200, :body => "", :headers => {})
webmock: forjando a resposta
Testes que acessam rede
spec/services/criador_pokemon_spec.rb
describe 'pokemon criado' do
before do
body = '{' 
' "name": "Charizard"' 
'}'
stub_request(:get, 'http://pokeapi.co/api/v1/pokemon/6/')
.to_return(status: 200, body: body, headers: {})
criador_pokemon.criar
end
end
webmock: forjando com cURL
Testes que acessam rede
bash
$ curl -is http://pokeapi.co/api/v1/pokemon/6/ > 
spec/fixtures/services/criador_pokemon/resposta.txt
spec/services/criador_pokemon_spec.rb
describe 'pokemon criado' do
before do
caminho_arquivo = 'spec/fixtures/services/criador_pokemon/resposta.txt'
arquivo_resposta = File.new(caminho_arquivo)
stub_request(:get, 'http://pokeapi.co/api/v1/pokemon/6/')
.to_return(arquivo_resposta)
criador_pokemon.criar
end
end
vcr
Testes que acessam rede
vcr: con!guração
Testes que acessam rede
spec/support/vcr.rb
VCR.configure do |c|
c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
c.hook_into :webmock
end
vcr: feedback rápido
Testes que acessam rede
bash
Failure/Error: CriadorPokemon.new(6)
VCR::Errors::UnhandledHTTPRequestError:
=====================================================================
An HTTP request has been made that VCR does not know how to handle:
GET http://pokeapi.co/api/v1/pokemon/6/
There is currently no cassette in use. There are a few ways
you can configure VCR to handle this request:
...
vcr: forjando a resposta
Testes que acessam rede
spec/services/criador_pokemon_spec.rb
describe 'pokemon criado' do
before do
VCR.use_cassette('CriadorPokemon/criar') do
criador_pokemon.criar
end
end
#...
it 'possui o nome correto' do
expect(subject.nome).to eq('Charizard')
end
end
vcr: RSpec metadata
Testes que acessam rede
spec/support/vcr.rb
VCR.configure do |c|
# ...
c.configure_rspec_metadata!
end
spec/spec_helper.rb
RSpec.configure do |config|
# ...
config.treat_symbols_as_metadata_keys_with_true_values = true
end
spec/services/criador_pokemon_spec.rb
describe 'pokemon criado', :vcr do
before do
criador_pokemon.criar
end
#...
it 'possui o nome correto' do
expect(subject.nome).to eq('Charizard')
end
end
factory_girl
!xtures X factories
factory_girl
criando uma factory
factory_girl
spec/factories/usuarios.rb
FactoryGirl.define do
factory :usuario do
nome 'Mauro'
email 'mauro@helabs.com.br'
end
end
console rails
FactoryGirl.create(:usuario)
FactoryGirl.create(:usuario, email: 'mauro@helabs.com.br')
con!gurando
factory_girl
spec/spec_helper.rb
RSpec.configure do |config|
# ...
config.include FactoryGirl::Syntax::Methods
end
Em um teste qualquer
let!(:artigo) do
create(:artigo)
end
attributes_for
factory_girl
spec/controllers/posts_controller_spec.rb
describe "POST 'create'" do
let(:params) do
{
artigo: {
titulo: 'Meu titulo',
conteudo: 'Conteudo do artigo'
}
}
end
end
spec/controllers/posts_controller_spec.rb
describe "POST 'create'" do
let(:params) do
{ artigo: attributes_for(:artigo) }
end
end
herança
factory_girl
spec/factories/artigos.rb
factory :artigo do
titulo 'Diversas dicas do RSpec'
conteudo 'Conteúdo de Diversas dicas do RSpec'
factory :artigo_aprovado do
aprovado true
end
factory :artigo_nao_aprovado do
aprovado false
end
end
console rails
FactoryGirl.create(:artigo_aprovado)
FactoryGirl.create(:artigo_nao_aprovado)
traits
factory_girl
spec/factories/artigos.rb
factory :artigo do
titulo 'Diversas dicas do RSpec'
conteudo 'Conteúdo de Diversas dicas do RSpec'
trait :aprovado do
aprovado true
end
trait :nao_aprovado do
aprovado false
end
end
console rails
FactoryGirl.create(:artigo, :aprovado)
FactoryGirl.create(:artigo, :nao_aprovado)
dependent attributes
factory_girl
spec/factories/artigos.rb
factory :artigo do
titulo 'Diversas dicas do RSpec'
conteudo { "Conteúdo do artigo #{titulo}. Aprovado: #{aprovado}" }
end
sequence
factory_girl
spec/factories/artigos.rb
factory :artigo do
sequence(:titulo) { |n| "Diversas dicas do RSpec #{n}" }
conteudo { "Conteúdo do artigo #{titulo}. Aprovado: #{aprovado}" }
end
associações
factory_girl
console rails
usuario = FactoryGirl.create(:usuario)
FactoryGirl.create(:artigo, usuario: usuario)
spec/factories/artigos.rb
factory :artigo do
titulo 'Diversas dicas do RSpec'
conteudo { "Conteúdo do artigo #{titulo}. Aprovado: #{aprovado}" }
usuario
end
aliases
factory_girl
spec/factories/artigos.rb
factory :usuario, aliases: [:autor] do
nome 'Mauro'
email { "#{nome}@helabs.com.br" }
end
strategies
factory_girl
console rails
pokemon = FactoryGirl.build(:pokemon)
console rails
pokemon = FactoryGirl.build_stubbed(:pokemon)
lint
factory_girl
spec/support/factory_girl.rb
RSpec.configure do |config|
config.before(:suite) do
begin
DatabaseCleaner.start
FactoryGirl.lint
ensure
DatabaseCleaner.clean
end
end
end
timecop
app/models/pokemon.rb
class Pokemon < ActiveRecord::Base
scope :escolhidos_ontem, -> do
where(escolhido_em: 1.day.ago.midnight..Time.zone.now.midnight)
end
end
spec/models/pokemon_spec.rb
describe '.escolhidos_ontem' do
let!(:pokemon_escolhido_ontem) do
create(:pokemon, escolhido_em: Time.zone.local(2014, 8, 6, 17, 15))
end
subject do
Pokemon.escolhidos_ontem
end
it 'tem o pokemon escolhido ontem' do
expect(subject).to include(pokemon_escolhido_ontem)
end
end
spec/models/pokemon_spec.rb
describe '.escolhidos_ontem' do
# ...
it 'tem o pokemon escolhido ontem' do
Timecop.freeze(Time.zone.local((2014, 8, 7, 17, 15)) do
expect(subject).to include(pokemon_escolhido_ontem)
end
end
end
simplecov
veri!cando a cobertura
simplecov
spec/spec_helper.rb
require 'simplecov'
SimpleCov.start 'rails'
Primeira linha do
spec_helper.rb
O falso 100%
simplecov
app/models/pokemon.rb
class Pokemon < ActiveRecord::Base
validates :nome, :id_nacional, presence: true
scope :escolhidos_ontem, -> do
where(escolhido_em: 1.day.ago.midnight..Time.zone.now.midnight)
end
end
Não teste associações, validações ou
escopos do Active Record
simplecov
teste associações, validações e escopos do
Active Record
simplecov
devo ter 100% de cobertura de testes?
simplecov
shoulda-matchers
app/models/pokemon.rb
class Pokemon < ActiveRecord::Base
validates :nome, :id_nacional, presence: true
validates :id_nacional, numericality: { only_integer: true, greater_than: 0 }
end
spec/models/pokemon_spec.rb
describe 'validações' do
it { is_expected.to validate_presence_of(:nome) }
it { is_expected.to validate_presence_of(:id_nacional) }
it { is_expected.to validate_numericality_of(:id_nacional).only_integer
.is_greater_than(0) }
end
ActiveModel
ActiveRecord
ActionController
os matchers
shoulda-matchers
https://github.com/bmabey/email-spec
https://github.com/philostler/rspec-sidekiq
https://github.com/evansagge/mongoid-rspec
além do shoulda-matchers
shoulda-matchers
Obrigado!
maurogeorge.com.br

Mais conteúdo relacionado

Destaque

Aprendendo com projetos open source @ RubyConf 2015
Aprendendo com projetos open source @ RubyConf 2015Aprendendo com projetos open source @ RubyConf 2015
Aprendendo com projetos open source @ RubyConf 2015Mauro George
 
O cliente e o time juntos por um só objetivo! @ CONADEV 2014
O cliente e o time juntos por um só objetivo! @ CONADEV 2014O cliente e o time juntos por um só objetivo! @ CONADEV 2014
O cliente e o time juntos por um só objetivo! @ CONADEV 2014Mauro George
 
Git para iniciantes v1.3.0 @ PHP Conference Brasil 2012
Git para iniciantes v1.3.0 @ PHP Conference Brasil 2012Git para iniciantes v1.3.0 @ PHP Conference Brasil 2012
Git para iniciantes v1.3.0 @ PHP Conference Brasil 2012Mauro George
 
Model of the colossus @ Rupy Brazil 2013
Model of the colossus @ Rupy Brazil 2013 Model of the colossus @ Rupy Brazil 2013
Model of the colossus @ Rupy Brazil 2013 Mauro George
 
Testes automatizados o time e o cliente saem ganhando! @ Agile Vale 2014
Testes automatizados o time e o cliente saem ganhando! @ Agile Vale 2014Testes automatizados o time e o cliente saem ganhando! @ Agile Vale 2014
Testes automatizados o time e o cliente saem ganhando! @ Agile Vale 2014Mauro George
 
Rails front-end com bourbon e sua familia @ Front in Maceió 2014
Rails front-end com bourbon e sua familia @ Front in Maceió 2014Rails front-end com bourbon e sua familia @ Front in Maceió 2014
Rails front-end com bourbon e sua familia @ Front in Maceió 2014Mauro George
 
Minicurso Git Semcomp Beta
Minicurso Git   Semcomp BetaMinicurso Git   Semcomp Beta
Minicurso Git Semcomp BetaBruno Orlandi
 
TDC2016POA | Trilha Empreendedorismo - Faça mais, reclame menos.
TDC2016POA | Trilha Empreendedorismo - Faça mais, reclame menos.TDC2016POA | Trilha Empreendedorismo - Faça mais, reclame menos.
TDC2016POA | Trilha Empreendedorismo - Faça mais, reclame menos.tdc-globalcode
 
TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...
TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...
TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...tdc-globalcode
 
Aula 4 - Curso Git e Github - Webschool
Aula 4 - Curso Git e Github - WebschoolAula 4 - Curso Git e Github - Webschool
Aula 4 - Curso Git e Github - WebschoolBruno Orlandi
 
Aula 6 - Curso Git e Github - Webschool
Aula 6 - Curso Git e Github - WebschoolAula 6 - Curso Git e Github - Webschool
Aula 6 - Curso Git e Github - WebschoolBruno Orlandi
 
Aula 5 - Curso Git e Github - Webschool
Aula 5 - Curso Git e Github - WebschoolAula 5 - Curso Git e Github - Webschool
Aula 5 - Curso Git e Github - WebschoolBruno Orlandi
 
Git e contibuição com projetos open source usando GitHub
Git e contibuição com projetos open source usando GitHubGit e contibuição com projetos open source usando GitHub
Git e contibuição com projetos open source usando GitHubBruno Orlandi
 
Aula 2 - Curso Git e Github - Webschool
Aula 2 - Curso Git e Github - WebschoolAula 2 - Curso Git e Github - Webschool
Aula 2 - Curso Git e Github - WebschoolBruno Orlandi
 
Mini-curso de git -- SECOMP-UFS
Mini-curso de git -- SECOMP-UFSMini-curso de git -- SECOMP-UFS
Mini-curso de git -- SECOMP-UFSFelipe Carvalho
 
Use o git e perca o medo de errar
Use o git e perca o medo de errarUse o git e perca o medo de errar
Use o git e perca o medo de errarBruno Calheira
 

Destaque (20)

Aprendendo com projetos open source @ RubyConf 2015
Aprendendo com projetos open source @ RubyConf 2015Aprendendo com projetos open source @ RubyConf 2015
Aprendendo com projetos open source @ RubyConf 2015
 
O cliente e o time juntos por um só objetivo! @ CONADEV 2014
O cliente e o time juntos por um só objetivo! @ CONADEV 2014O cliente e o time juntos por um só objetivo! @ CONADEV 2014
O cliente e o time juntos por um só objetivo! @ CONADEV 2014
 
Git para iniciantes v1.3.0 @ PHP Conference Brasil 2012
Git para iniciantes v1.3.0 @ PHP Conference Brasil 2012Git para iniciantes v1.3.0 @ PHP Conference Brasil 2012
Git para iniciantes v1.3.0 @ PHP Conference Brasil 2012
 
Model of the colossus @ Rupy Brazil 2013
Model of the colossus @ Rupy Brazil 2013 Model of the colossus @ Rupy Brazil 2013
Model of the colossus @ Rupy Brazil 2013
 
Testes automatizados o time e o cliente saem ganhando! @ Agile Vale 2014
Testes automatizados o time e o cliente saem ganhando! @ Agile Vale 2014Testes automatizados o time e o cliente saem ganhando! @ Agile Vale 2014
Testes automatizados o time e o cliente saem ganhando! @ Agile Vale 2014
 
O efeito borboleta ágil: Do caos ao hackathon
O efeito borboleta ágil: Do caos ao hackathonO efeito borboleta ágil: Do caos ao hackathon
O efeito borboleta ágil: Do caos ao hackathon
 
Rails front-end com bourbon e sua familia @ Front in Maceió 2014
Rails front-end com bourbon e sua familia @ Front in Maceió 2014Rails front-end com bourbon e sua familia @ Front in Maceió 2014
Rails front-end com bourbon e sua familia @ Front in Maceió 2014
 
Minicurso Git Semcomp Beta
Minicurso Git   Semcomp BetaMinicurso Git   Semcomp Beta
Minicurso Git Semcomp Beta
 
TDC2016POA | Trilha Empreendedorismo - Faça mais, reclame menos.
TDC2016POA | Trilha Empreendedorismo - Faça mais, reclame menos.TDC2016POA | Trilha Empreendedorismo - Faça mais, reclame menos.
TDC2016POA | Trilha Empreendedorismo - Faça mais, reclame menos.
 
TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...
TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...
TDC2016POA | Trilha Ruby - Testes de contrato em um contexto de services e mi...
 
Minicurso Git
Minicurso GitMinicurso Git
Minicurso Git
 
Aula 4 - Curso Git e Github - Webschool
Aula 4 - Curso Git e Github - WebschoolAula 4 - Curso Git e Github - Webschool
Aula 4 - Curso Git e Github - Webschool
 
Aula 6 - Curso Git e Github - Webschool
Aula 6 - Curso Git e Github - WebschoolAula 6 - Curso Git e Github - Webschool
Aula 6 - Curso Git e Github - Webschool
 
Aula 5 - Curso Git e Github - Webschool
Aula 5 - Curso Git e Github - WebschoolAula 5 - Curso Git e Github - Webschool
Aula 5 - Curso Git e Github - Webschool
 
Git e contibuição com projetos open source usando GitHub
Git e contibuição com projetos open source usando GitHubGit e contibuição com projetos open source usando GitHub
Git e contibuição com projetos open source usando GitHub
 
Aula 2 - Curso Git e Github - Webschool
Aula 2 - Curso Git e Github - WebschoolAula 2 - Curso Git e Github - Webschool
Aula 2 - Curso Git e Github - Webschool
 
Mini-curso de git -- SECOMP-UFS
Mini-curso de git -- SECOMP-UFSMini-curso de git -- SECOMP-UFS
Mini-curso de git -- SECOMP-UFS
 
Use o git e perca o medo de errar
Use o git e perca o medo de errarUse o git e perca o medo de errar
Use o git e perca o medo de errar
 
Git e GitHub - Conceitos Básicos
Git e GitHub - Conceitos BásicosGit e GitHub - Conceitos Básicos
Git e GitHub - Conceitos Básicos
 
Aprendendo Git
Aprendendo GitAprendendo Git
Aprendendo Git
 

RSpec Best Friends @ TDC São Paulo 2014