12. Testes Unitários
Unidade é a menor parte testável de
um software.
Consigo encontrar o erro com mais
eficiência.
Como “escapar” da dependência entre
as camadas?
13. Stub Methods
Simula o comportamento de um código
existente.
Reduz o tempo de execução.
Isola o teste.
14. O Método
def create
@sorteio = Sorteio.new(params[:sorteio])
if @sorteio.save
redirect_to @sorteio, notice: 'Sorteio criado.'
else
render action: "new"
end
end
15. O Teste
context "se sorteio for salvo com sucesso" do
before do
Sorteio.any_instance.stub(:save).and_return(true)
end
it "deve enviar pra tela de sorteios" do
post :create, :id => 1
response.should redirect_to sorteios_path
end
end
16. Mock Objects
Objetos “de mentira” ou objetos
substitutos.
Permitem isolar as classes de um
sistema de forma bastante simples.
17. O Método
def sortear
@sorteio = Sorteio.find(params[:id])
@sorteio.sortear
redirect_to sorteio_path(@sorteio_id),
notice: 'Sorteio realizado.'
end
18. O Teste
before do
@sorteio = mock('Sorteio')
@sorteio.stub(:sortear)
Sorteio.stub(:find).and_return(@sorteio)
end
it "deve mostrar mensagem de sorteio realizado" do
get :sortear, :id => 1
flash[:notice].should == "Sorteio realizado."
end
21. O Teste
it "popula sorteio com o sorteio enviado" do
sorteio = mock('Sorteio')
Sorteio.should_receive(:find).with('1')
.and_return(sorteio)
get :edit, :id => 1
assigns[:sorteio].should == sorteio
end
23. context "se concorrente não for salvo" do
before do
@concorrente_mock.stub(:save).and_return(false)
end
it "deve enviar pra tela de apresentação do sorteio
deste concorrente" do
post :create, :sorteio_id => 1
response.should redirect_to sorteio_path(1)
end
it "deve enviar uma notificação de Houve um erro na
criação do Concorrente." do
post :create, :sorteio_id => 1
flash[:notice].should == "Houve um erro na criação
do Concorrente."
end
end
24. Rotas
Sorteando::Application.routes.draw do
resources :sorteios do
member do
get :sortear
end
resources :concorrentes, :only => [:new, :create, :destroy]
end
root :to => 'sorteios#index'
end
25. Testando Rotas
it "routes to #create" do
post("/sorteios/1/concorrentes").should
route_to("concorrentes#create", :sorteio_id => "1")
end
it "routes to #destroy" do
delete("/sorteios/1/concorrentes/2").should
route_to("concorrentes#destroy", :sorteio_id => "1",
:id => "2")
end
it "routes to #index" do
get("/sorteios/1/concorrentes").should_not be_routable
end
26. Testes de Models
Objetos Reais.
Usar somente as propriedades
necessárias.
Validação de Campo Obrigatório.
28. #sorteio.rb
FactoryGirl.define do
factory :sorteio do
sequence(:nome) { |n| "sorteio_#{n}" }
qtd_premios 1
end
end
#concorrente.rb
FactoryGirl.define do
factory :concorrente do
sequence(:nome) { |n| "nome_#{n}" }
sequence(:email) { |n| "nome_#{n}@email.com" }
association :sorteio
end
end
30. describe "Validations" do
it { should validate_presence_of(:nome).with_message(/é um
campo obrigatório/) }
it { should validate_presence_of(:qtd_premios).with_message(/é
um campo obrigatório/) }
end
it "sortear com quantidade menor que a quantidade de prêmios" do
sorteio = FactoryGirl.create(:sorteio, :qtd_premios => 3)
conc1 = FactoryGirl.create(:concorrente, :sorteio => sorteio)
conc2 = FactoryGirl.create(:concorrente, :sorteio => sorteio)
sorteio.sortear
sorteio.vencedores.should have(2).vencedores
end
32. describe "sorteios/index" do
it "mostrar titulo Sorteios" do
assign :sorteios, []
render
rendered.should have_content("Sorteios")
end
it "mostrar listagem de sorteios" do
assign :sorteios, [ FactoryGirl.build(:sorteio,
:id => '1',
:nome => 'mega sena da virada') ]
render
rendered.should have_selector("tr > td") do |td|
td.should have_content('mega sena da virada')
end
end
end
40. Refactoring e teste
volta a Falhar
def eh_vencedor?
VencedorSorteio.where(:concorrente_id => self).exists?
end
41. Teste “Passando”
Novamente
it "#eh_vencedor?" do
sorteio = FactoryGirl.create(:sorteio)
concorrente = FactoryGirl.create(:concorrente,
:sorteio => sorteio)
concorrente.eh_vencedor?.should == false
end
42. Refactoring
describe "#eh_vencedor?" do
it "Se não venceu o sorteio, retorna falso" do
sorteio = FactoryGirl.create(:sorteio)
concorrente = FactoryGirl.create(:concorrente,
:sorteio => sorteio)
concorrente.eh_vencedor?.should == false
end
it "Se venceu o sorteio, retorna verdadeiro" do
sorteio = FactoryGirl.create(:sorteio)
concorrente = FactoryGirl.create(:concorrente,
:sorteio => sorteio)
sorteio.vencedores << concorrente
sorteio.save
concorrente.eh_vencedor?.should == true
end
end
46. Usando o Capybara
it "fluxo completo de cadastro" do
visit "/sorteios"
click_link('+')
fill_in('Nome', :with => 'Livro de Testes Automatizados')
fill_in('Qtd de Premios', :with => '1')
click_button('Novo')
page.should have_content("Sorteio criado.")
page.should have_content("Livro de Testes Automatizados")
page.should have_content("Concorrentes: +")
end
48. Criando Steps
Dado /^que estou na página "(.*?)"$/ do |pagina|
visit pagina
end
Então /^devo ver o texto "(.*?)"$/ do |texto|
page.should have_content(texto)
end
Quando /^clicar no link "(.*?)"$/ do |link|
click_link(link)
end
Quando /^clicar no botao "(.*?)"$/ do |botao|
click_button(botao)
end
49. Usando o Cucumber
Cenário: Cadastrando um sorteio
Dado que estou na página "/sorteios"
Quando clicar no link "+"
Então devo mudar a pagina
Quando preencher o campo "Nome" com "Livro de
Testes Automatizados"
E preencher o campo "Qtd de Premios" com "1"
E clicar no botao "Novo"
Então devo mudar a pagina
Então devo ver o texto "Sorteio criado."
E devo ver o texto "Livro de Testes Automatizados"
E devo ver o texto "Concorrentes: +"
50. Integração Continua
Membros de um time integram seu
trabalho frequentemente.
Podem haver multiplas integrações por
dia.
Cada integração é verificada por um
build automatizado.