cuso ruby - aula 05 - testes com rspec
DESCRIPTION
Material de apoio da aula de testes com RSpec do curso de Rails.TRANSCRIPT
Aprendendo Ruby on Rails – Aula 5
– Testes com RSpec e Cucumber
Maurício Linhares
O que é o RSpec?
É um ferramenta de Behaviour Driven Development;
Uma solução simples para implementar testes de
unidade na sua aplicação;
Tem suporte direto a Rails para testar modelos,
helpers e controllers;
Adicionando o RSpec na sua aplicação Rails
– config/environments/test.rb
sudo gem install rspec rspec-rails factory_girl
remarkable_rails
# configurando as gems necessárias
config.gem 'rspec', :lib => false
config.gem 'rspec-rails', :lib => false
config.gem 'factory_girl'
config.gem 'remarkable_rails', :lib => false
config.gem 'remarkable_activerecord', :lib => false
Gerando o código inicial do RSpec
script/generate rspec
config.gem “factory_girl” ?
Gem de suporte a testes, ajuda a criar objetos para
os testes da aplicação;
É uma “fábrica de objetos” genéricos para evitar a
repetição de código para testes na aplicação;
Existem outras gems que executam o mesmo
trabalho, como “machinist”, todas fazem a mesma
coisa mas de formas diferentes;
As fábricas ficam em “spec/factories”;
Criando as sequências –
spec/factories/sequences.rb
Factory.sequence :nome do |n|
"Nome #{n}"
end
Factory.sequence :email do |n|
"eu_#{n}@mail.com"
end
Criando as fábricas – usuario_factory.rb
Factory.define :usuario do |f|
f.nome { Factory.next(:nome) }
f.email { Factory.next(:email) }
f.senha "123456"
f.senha_confirmation "123456"
f.ultimo_acesso_em { Time.now }
end
Criando as fábricas – produto_factory.rb
Factory.define :produto do |f|
f.nome { Factory.next(:nome) }
f.preco 10.0
f.descricao "Descrição de exemplo"
end
Criando as fábricas – item_factory.rb
Factory.define :item do |f|
f.quantidade 5
f.association :produto, :factory => :produto
f.association :pedido, :factory => :pedido
end
Criando as fábricas – pedido_factory.rb
Factory.define :pedido do |f|
f.estado 'carrinho'
end
Criando o spec de produto com Remarkable
require( File.expand_path( File.join( File.dirname(__FILE__), '..', 'spec_helper' ) ) )
describe Produto do
context 'ao ser validado' do
it { should validate_presence_of :nome }
it { should validate_presence_of :preco }
it { should validate_numericality_of :preco, :allow_blank => true, :greater_than => 0 }
end
end
Métodos do RSpec
“describe” – define a classe/objeto que está sendo
testado;
“context” – define o escopo no qual o objeto está
sendo testado
“it” – define o teste que vai ser executado
“before” – define um bloco de código que é utilizado
para inicializar os objetos antes do teste
Criando o spec pra Itemrequire( File.expand_path( File.join( File.dirname(__FILE__), '..', 'spec_helper' ) ) )
describe Item do
context 'ao ser associado a outros objetos' do
it { should belong_to(:pedido) }
it { should belong_to(:produto) }
end
context 'ao se calcular preços' do
before do
@produto = Factory(:produto, :preco => 20)
@item = Factory( :item, :produto => @produto , :quantidade => 6 )
end
it 'deve ter como preço 120' { @item.preco_total.should == 120 }
end
end
Criando o spec para Pedidocontext 'em operacoes' do
before do
@produto_1 = Factory( :produto, :preco => 10 )
@produto_2 = Factory( :produto, :preco => 20 )
@produto_3 = Factory( :produto, :preco => 30 )
@pedido = Factory( :pedido )
end
it 'deve ter como preço total a suma dos preços individuais dos itens' do
@pedido.adicionar_produto( @produto_1, 2 )
@pedido.adicionar_produto( @produto_2, 5 )
@pedido.preco_total.should == 120
end
end
Criando o spec para o Pedidocontext 'em operacoes' do
context 'na implementação de blank' do
it 'deve retornar verdadeiro se o pedido estiver vazio' do
@pedido.should be_blank
end
it 'deve retornar false se o pedido não estiver vazio' do
@pedido.adicionar_produto( @produto_1, 3 )
@pedido.should_not be_blank
end
end
end
Criando o spec de Pedidocontext 'ao unir pedidos' do
before do
@pedido.adicionar_produto( @produto_1, 2 )
@pedido.adicionar_produto( @produto_2, 3 )
@pedido_2 = Factory(:pedido)
@pedido_2.adicionar_produto( @produto_2, 2 )
@pedido_2.adicionar_produto( @produto_3, 3 )
@pedido.unir( @pedido_2 )
end
it 'o pedido final deve ter o total de itens dos dois pedidos' do
@pedido.item_por_produto( @produto_1 ).quantidade.should == 2
@pedido.item_por_produto( @produto_2 ).quantidade.should == 5
@pedido.item_por_produto( @produto_3 ).quantidade.should == 3
end
end
Criando o spec de Pedidocontext 'ao adicionar um produto ao pedido' do
before do
@pedido.adicionar_produto( @produto_1, 5 )
end
it 'deve adicionar um produto como item do pedido' do
@pedido.itens.size.should == 1
end
it 'deve adicionar o produto corretamente' do
@pedido.itens.first.produto == @produto_1
end
it 'deve aumentar a quantidade de itens ao adicionar o mesmo item denovo' do
@pedido.adicionar_produto( @produto_1, 3 )
@pedido.itens.first.quantidade.should == 8
end
end
Criando o spec de Pedidocontext 'deve remover itens zerados após salvar o pedido' do
before do
@pedido.adicionar_produto(@produto_1, 1)
@pedido.adicionar_produto(@produto_2, 2)
@pedido.save!
end
it 'deve remover o produto' do
@pedido.itens.last.update_attribute( :quantidade, 0 )
@pedido.save!
@pedido.item_por_produto( @produto_2 ).should be_nil
end
end
Criando o spec de Usuariocontext 'em associações' do
it { should have_many(:pedidos) }
it { should have_one(:pedido_atual) }
end
context 'em validações' do
it { should validate_presence_of( :nome ) }
it { should validate_presence_of( :email ) }
it { should validate_acceptance_of(:termos_e_condicoes) }
it { should validate_presence_of(:senha_em_hash, :if => :senha_necessaria?) }
it { should validate_length_of(:senha, :within => 4..40, :if => :senha_necessaria?) }
it { should validate_confirmation_of(:senha, :if => :senha_necessaria?) }
end
Criando a spec de Usuariocontext 'em chamadas de senha_necessaria?' do
before do
@usuario = Factory(:usuario)
@usuario.senha = nil
end
it 'deve retornar false quando o hash da senha não for vazio' do
@usuario.senha_necessaria?.should be_false
end
it 'deve retornar true quando a senha for preenchida' do
@usuario.senha = "123456"
@usuario.senha_necessaria?.should be_true
end
it 'deve retornar true quando o hash da senha for vazio' do
@usuario.senha_em_hash = nil
@usuario.senha_necessaria?.should be_true
end
end
Criando a spec de Usuario
context 'ao criar um usuário' do
before do
@usuario = Factory.build(:usuario)
end
it 'deve enviar um email' do
UsuariosMailer.should_receive( :deliver_registro).with(@usuario)
@usuario.save!
end
end
Criando a spec de Usuariocontext 'em chamadas de autenticação' do
before do
@usuario = Factory(:usuario,
:senha => '123456',
:senha_confirmation => '123456')
end
it 'deve autenticar o usuário se estiver com a senha correta' do
Usuario.autenticar(@usuario.email, '123456').should == @usuario
end
it 'não deve autenticar se a senha estiver errada' do
Usuario.autenticar( @usuario.email, "654321" ).should be_nil
end
end
Criando spec para SessoesController
context 'em chamadas pra se fazer o login do usuario' do
before do
@usuario = Factory(:usuario, :senha => "123456", :senha_confirmation => '123456')
end
def do_post( senha, email = @usuario.email )
post :create, :email => email, :senha => senha
end
end
Criando spec para SessoesControllercontext 'com dados corretos' do
it 'deve colocar o usuario na sessao' do
do_post( '123456' )
session[:usuario_id].should == @usuario.id
end
it 'deve redirecionar para a listagem de produtos' do
do_post( '123456' )
response.should redirect_to( produtos_path )
end
it 'deve colocar uma mensagem na flash' do
do_post('123456')
flash[:aviso].should == "Seja bem vindo a nossa loja, #{@usuario.nome}"
end
end
Criando spec para SessoesControllercontext 'com dados incorretos' do
it 'deve mostrar a página new' do
do_post( 'falso!' )
response.should render_template(:new)
end
it 'deve colocar uma mensagem na flash' do
do_post('falso!')
response.flash[:erro].should == "Não foi encontrado um usuário com o email e a senha que você forneceu"
end
end