SlideShare uma empresa Scribd logo
1 de 52
Testes unitários e de integração




         Quando e Porque




                 
Resumo


    Introdução
    Testes unitários
    Testes de integração
    Desenvolvimento outside-in
    Conclusão



                            
O porque inicial...

    Tudo muda o tempo todo




                          
Testes unitários



     Testando a menor unidade de código
    possível da forma mais isolada possível




                        
Unitários: Exemplo inicial
describe Jogador do

 let(:objetivo) { double }
 subject { Jogador.new(objetivo) }

 describe '#venceu?' do

   it "deveria ser true se completou objetivo" do
     objetivo.stub!(:completo?) { true }
     subject.venceu?.should be
   end
 end

end
                                      
Unitários: Código testado

class Jogador
 def initialize(objetivo)
   @objetivo = objetivo
 end
 def venceu?
   @objetivo.completo?
 end
end


                        
Unitários: Exemplo + completo
describe Jogador do

 let(:objetivo) { double }
 let(:partida) { double }
 subject { Jogador.new(partida, objetivo) }

 describe '#venceu?' do

     #...

      it "deveria informar partida e jogador ao objetivo" do
        objetivo.should_receive(:completo?).with( subject, partida )
        subject.venceu?
      end

 end

end

                                               
Unitários: Código testado

class Jogador
 def initialize(partida, objetivo)
   @objetivo = objetivo
   @partida = partida
 end
 def venceu?
   @objetivo.completo? self, @partida
 end
end

                      
Unitários: Ciclo do TDD


                  Crie um teste




       Refatore               Implemente a solução




                           
Unitários: Prós

    Rápido de fazer e executar
    Incentiva o baixo acoplamento
    Facilita resolução de algoritmos




                             
Unitários: Contras

    Falsa sensação de terminado
    Insegurança ao trocar contratos




                            
Unitários: Exemplo de erro

class Objetivo
 def completo?(jogador, partida)
 def terminado?(jogador, partida)
   #...
 end
end




                      
Testes de integração



    Testando para garantir que as classes
    e componentes estejam se integrando
               corretamente




                       
Integração: Exemplo

describe Jogador, "com objetivo de conquistar 24 territorios" do

 let(:objetivo) { Objetivos::Conquistar24Territorios }
 let(:partida) { Partida.new }
 subject { Jogador.create(partida: partida, objetivo: objetivo) }

 it "deveria vencer se tiver 24 territorios" do
   24.times { subject.territorios << Territorio.new }
   subject.venceu?.should be
 end
end


                                     
Integração:            Modulo de Objetivos


    module Objetivos

     class Conquistar24Territorios
      def self.completo?(jogador, partida)
        jogador.territorios.count >= 24
      end
     end

    end


                            
Integração: End to end

Comportamento do ponto de vista do usuário


Exemplo:
    Dado que o jogador tem 23 territórios
    E o objetivo dele é conquistar 24 territórios
    Quando o jogador conquistar 1 território
    E finalizar a rodada
    Então Jogador vence a partida


                                
Integração: Prós

    Garante o funcionamento do sistema
    Sensação de tarefa concluída




                           
Integração: Contras

    Testes mais lentos
    Dificuldade de entender origem de erros




                            
Como unir?


    Sensação de finalizado e segurança dos testes
     de integração end to end

    Facilidade, rapidez e desacoplamento
     proporcionados pelos testes unitários




                            
Desenvolvimento Outside-in


    Definir caso de aceitação
    Preparar teste end-to-end
    Desenvolver funcionalidade com TDD
    Repetir isso infinitamente




                              
Outside-in: Caso de aceitação



    Jogador com 4 exércitos em um território
    ataca território vizinho que possui apenas
             1 exército e o conquista




                         
Setup – inicialmente fake

    feature "Atacar" do

     scenario "territorio vizinho com 3 dados e conquistar" do
      dado_jogador_com_exercitos_no_pais(4, :brasil)
      dado_jogador_com_exercitos_no_pais(1, :argentina)
     end

     private

     def dado_jogador_com_exercitos_no_pais(exercitos, pais)
     end

    end


                                     
Acesso - falhando
    feature "Atacar" do

     before :each do
      @partida = Partida.create
     end

     scenario "territorio vizinho com 3 dados e conquistar" do
      jogador1 = dado_jogador_com_exercitos_no_pais(4, :brasil)
      jogador2 = dado_jogador_com_exercitos_no_pais(1, :argentina)
      dado_que_jogador_esta_logado(jogador1)
     end

     #...

     def dado_que_jogador_esta_logado(jogador)
      visit partida_path(@partida)
     end

    end
                                         
Acesso - funcionando
    models/partida.rb:
    class Partida < ActiveRecord::Base
    end

    config/routes.rb:
    War::Application.routes.draw do
     resources :partidas
    end

    controllers/partida_controller.rb:
    class PartidasController < ApplicationController
     def show
     end
    end

    Partidas/show.html.erb:
    <h1>Ok</h1>
                                    
Primeira interação - falhando

    scenario "territorio vizinho com 3 dados e conquistar" do
     #...
     dado_que_jogador_esta_logado(jogador1)
     quando_selecionar_territorio_que_vai_atacar(:brasil)
    end

    private

    #...

    def quando_selecionar_territorio_que_vai_atacar(pais)
     click_link pais.to_s
    end

                                
Primeira interação - funcionando

    views/partidas.html.erb:
    <a href="#">brasil</a>




                          
Mais interações - falhando

    scenario "territorio vizinho com 3 dados e conquistar" do
     #...
     quando_selecionar_territorio_que_vai_atacar(:brasil)
     quando_selecionar_territorio_atacado(:argentina)
     quando_confirmar_ataque
    end

    #...

    def quando_selecionar_territorio_atacado(pais)
     click_link pais.to_s
    end

    def quando_confirmar_ataque
     click_button 'Atacar'
    end
                                   
Mais interações - funcionando

    views/partidas.html.erb:
    <form>
     <a href="#">brasil</a>
     <a href="#">argentina</a>
     <input name="Atacar"
       value="Atacar" type="submit"/>
    </form>



                         
Verficação - falhando

    scenario "territorio vizinho com 3 dados e conquistar" do
     #...
     quando_confirmar_ataque
     entao_territorio_eh_conquistado(:argentina)
    end

    #...

    def entao_territorio_eh_conquistado(pais)
     find('#mensagem').text.strip
        .should == "Territorio '#{pais}' conquistado"
    end

                                  
Verificação - funcionando

    views/partidas.html.erb:
    <form>
     <a href="#">brasil</a>
     <a href="#">argentina</a>
     <input name="Atacar"
       value="Atacar" type="submit"/>
     <div id="mensagem">
        Territorio 'argentina' conquistado
     </div>
    </form>
                          
O que temos até agora?



    Teste   View       Controller   Model




                    
Teste end-to-end ok

    Hora de ir mais fundo
    TDD a todo momento




                             
Teste unitário do controller

describe AtaquesController, 'POST' do

     it 'deveria redirecionar para a partida' do
       post :create, partida_id: 1, ataque: {}
       response.should redirect_to(partida_path(1))
     end

     it 'deveria colocar mensagem de sucesso' do
       post :create, partida_id: 1, ataque: { pais_atacado: 'argentina' }
       flash[:mensagem].
          should == "Territorio 'argentina' conquistado"
     end

end

                                        
Controller de ataque

class AtaquesController < ApplicationController
 def create
   pais = params[:ataque][:pais_atacado]
   flash[:mensagem] = "Territorio #{pais}' conquistado"
   redirect_to partida_path(params[:partida_id])
 end
end




                             
View tem que mudar
    <div id="mensagem"><%= flash[:mensagem] %></div>

    <%= form_for :ataque,
        url: partida_ataques_url(@partida),
        method: :post do |f| %>

     <a href="#">brasil</a>
     <a href="#">argentina</a>

     <%= f.hidden_field 'pais_que_ataca' %>
     <%= f.hidden_field 'pais_atacado' %>

     <%= f.submit value: 'Atacar' %>

 
    <% end %>                  
Javascript incluído
    var paisQueAtaca = $('#ataque_pais_que_ataca');
    var paisAtacado = $('#ataque_pais_atacado');
    var paisAtual = paisQueAtaca;

    var marcar = function(texto) {
      paisAtual.val(texto);
    }
    var trocaPaisAtual = function() {
      paisAtual = paisAtual == paisQueAtaca ?
           paisAtacado : paisQueAtaca;
    }

    $('a').click(function(e){
        e.preventDefault();
        marcar($(this).text());
        trocaPaisAtual();
    });
                                   
O que temos até agora? (2)



    Teste   View       Controller   Model




                    
Teste unitário do controller
    describe AtaquesController, 'POST' do

     let(:partida) { double(id: 1, executar_ataque: true) }

     before :each do
      Partida.stub!(:find) { partida }
     end

     #...

     it 'deveria executar ataque na partida' do
       params_ataque = {"meu_ataque" => true}
       partida.should_receive(:executar_ataque).with(params_ataque)
       post :create, partida_id: 1, ataque: params_ataque
     end

    end
                                          
Controller de ataque

    class AtaquesController < ApplicationController
     def create
       ataque = params[:ataque]
       partida = Partida.find params[:partida_id]
       partida.executar_ataque(ataque)
       pais = ataque[:pais_atacado]
       flash[:mensagem] = "Territorio '#{pais}' conquistado"
       redirect_to partida_path(partida)
     end
    end



                               
Teste end-to-end falha

    $ rake spec:acceptance
    Failures:

     1) Atacar territorio vizinho com 3 dados e conquistar
       Failure/Error: find('#mensagem').text.strip.should == "Territorio...
       Capybara::ElementNotFound:
        Unable to find css "#mensagem"




          Erro dificil de encontrar a origem!


                                       
Método não encontrado

    $ tail -f log/test.log
    Completed 500 Internal Server Error in 3ms
    undefined method `executar_ataque' for #<Partida:0xa5549c0>




        class Partida < ActiveRecord::Base
         def executar_ataque(attrs)
         end
        end


                                 
Um pouco de ousadia



    Que tal começar um outro caso
    de aceitação antes de terminar
                este?




                    
Caso da derrota
scenario "territorio vizinho com 3 dados e conquistar", js: true do
 dado_que_dados_vermelhos_estao_sortudos
 #...
end
scenario "territorio vizinho com 3 dados e nao conquistar", js: true do
 dado_que_dados_vermelhos_estao_azarentos
 #...
end

def dado_que_dados_vermelhos_estao_azarentos
  ENV["forcar_vitoria"] = "defesa"
end
def dados_que_dados_vermelhos_estao_sortudos
  ENV["forcar_vitoria"] = "ataque"
end
                                    
Teste do controller
    context 'conquistando' do
     before :each do
       partida.stub!(:executar_ataque) { true }
     end
     it 'deveria colocar mensagem de sucesso' do
       post :create, partida_id: 1, ataque: { pais_atacado: 'argentina' }
       flash[:mensagem].should == "Territorio 'argentina' conquistado"
     end
    end
    context 'nao conquistando' do
     before :each do
       partida.stub!(:executar_ataque) { false }
     end
     it 'deveria colocar mensagem de insucesso' do
       post :create, partida_id: 1, ataque: { pais_atacado: 'argentina' }
       flash[:mensagem].should == "Territorio 'argentina' nao foi conquistado"
     end
    end

                                        
Controller de ataque

class AtaquesController < ApplicationController
 def create
   ataque = params[:ataque]
   partida = Partida.find params[:partida_id]
   pais = ataque[:pais_atacado]
   if partida.executar_ataque(ataque)
     flash[:mensagem] = "Territorio '#{pais}' conquistado"
   else
     flash[:mensagem] = "Territorio '#{pais}' nao foi conquistado"
   end
   redirect_to partida_path(partida)
 end
end

                                
Metodo burro pro teste passar


    class Partida < ActiveRecord::Base
     def executar_ataque(attrs)
       ENV["forcar_vitoria"] != 'defesa'
     end
    end



                        
O que temos até agora? (3)



    Teste   View       Controller   Model




                    
Integração com os models



        Dever de casa




                
Ciclo do outside-in


               Crie um teste
                end-to-end




                                              Crie um teste

    Refatore


                                   Refatore         Implemente a solução




                                
Conclusão

    Sempre guie o desenvolvimento por testes
    Tanto por testes de integração como unitários
    Combine-os em uma estratégia outside-in
    Siga sempre o mantra dos pequenos passos




                             
Bibliografia

    Test Driven Development: By Example
    Kent Beck

    Working Effectively with Legacy Code
    Michael Feathers

    Growing Object-Oriented Software, Guided by Tests
    Steve Freeman



                                 
Mantenha contato

timotta@gmail.com

@timotta

http://programandosemcafeina.blogspot.com




                      

Mais conteúdo relacionado

Destaque

Instructivo definitivo pregrado
Instructivo definitivo pregradoInstructivo definitivo pregrado
Instructivo definitivo pregradomoiseslogronog
 
Presentacion medytronic laboratorio(20.09)x
Presentacion medytronic laboratorio(20.09)xPresentacion medytronic laboratorio(20.09)x
Presentacion medytronic laboratorio(20.09)xqualytechsac
 
Presentacion de prueba
Presentacion de pruebaPresentacion de prueba
Presentacion de pruebarosarpabon
 
Presentacion de tres
Presentacion de tresPresentacion de tres
Presentacion de tresjosabet11
 
Trabajo slideshare
Trabajo slideshareTrabajo slideshare
Trabajo slideshareLUIZZXX
 
Jornal Daqui: notícias da Lagoinha e região
Jornal Daqui: notícias da Lagoinha e regiãoJornal Daqui: notícias da Lagoinha e região
Jornal Daqui: notícias da Lagoinha e regiãolorenatarcia
 
Wittgenstein, ludwig tractatus logico-philosophicus biling
Wittgenstein, ludwig   tractatus logico-philosophicus bilingWittgenstein, ludwig   tractatus logico-philosophicus biling
Wittgenstein, ludwig tractatus logico-philosophicus bilingmcpadre
 
Alimentos transgénicos05
Alimentos transgénicos05Alimentos transgénicos05
Alimentos transgénicos05adrianobando205
 
Colecistitis aguda y cronica.
Colecistitis aguda y cronica.Colecistitis aguda y cronica.
Colecistitis aguda y cronica.Laura Moreno
 
exposición introducción a la ing sistema
exposición introducción a la ing sistema   exposición introducción a la ing sistema
exposición introducción a la ing sistema Ernesto Barros Meza
 

Destaque (20)

Instructivo definitivo pregrado
Instructivo definitivo pregradoInstructivo definitivo pregrado
Instructivo definitivo pregrado
 
Presentacion medytronic laboratorio(20.09)x
Presentacion medytronic laboratorio(20.09)xPresentacion medytronic laboratorio(20.09)x
Presentacion medytronic laboratorio(20.09)x
 
Nova Igreja
Nova IgrejaNova Igreja
Nova Igreja
 
Los animalesblogger
Los animalesbloggerLos animalesblogger
Los animalesblogger
 
Guia 2 actividad 2
Guia 2 actividad 2Guia 2 actividad 2
Guia 2 actividad 2
 
Presentacion de prueba
Presentacion de pruebaPresentacion de prueba
Presentacion de prueba
 
Presentacion de tres
Presentacion de tresPresentacion de tres
Presentacion de tres
 
Trabajo slideshare
Trabajo slideshareTrabajo slideshare
Trabajo slideshare
 
Orlando Junior
Orlando JuniorOrlando Junior
Orlando Junior
 
Jornal Daqui: notícias da Lagoinha e região
Jornal Daqui: notícias da Lagoinha e regiãoJornal Daqui: notícias da Lagoinha e região
Jornal Daqui: notícias da Lagoinha e região
 
Wittgenstein, ludwig tractatus logico-philosophicus biling
Wittgenstein, ludwig   tractatus logico-philosophicus bilingWittgenstein, ludwig   tractatus logico-philosophicus biling
Wittgenstein, ludwig tractatus logico-philosophicus biling
 
Gpt cpe gerentes estrategicos
Gpt cpe gerentes estrategicosGpt cpe gerentes estrategicos
Gpt cpe gerentes estrategicos
 
Maka111
Maka111Maka111
Maka111
 
carelis pacheco
carelis pachecocarelis pacheco
carelis pacheco
 
Alimentos transgénicos05
Alimentos transgénicos05Alimentos transgénicos05
Alimentos transgénicos05
 
Colecistitis aguda y cronica.
Colecistitis aguda y cronica.Colecistitis aguda y cronica.
Colecistitis aguda y cronica.
 
exposición introducción a la ing sistema
exposición introducción a la ing sistema   exposición introducción a la ing sistema
exposición introducción a la ing sistema
 
Colegio nacional nicolás esguerra trabajo nº1
Colegio nacional nicolás esguerra trabajo nº1Colegio nacional nicolás esguerra trabajo nº1
Colegio nacional nicolás esguerra trabajo nº1
 
Orientacion profecional
Orientacion profecionalOrientacion profecional
Orientacion profecional
 
Menopausia
MenopausiaMenopausia
Menopausia
 

Semelhante a Testes automatizados de software

Introdução aos testes unitários
Introdução aos testes unitáriosIntrodução aos testes unitários
Introdução aos testes unitáriosoverduka
 
Design de código: princípios e práticas para ter um código sustentável
Design de código: princípios e práticas para ter um código sustentávelDesign de código: princípios e práticas para ter um código sustentável
Design de código: princípios e práticas para ter um código sustentávelAndrews Medina
 
Testes automatizados
Testes automatizadosTestes automatizados
Testes automatizadosRodrigo Maia
 
TDC2016 Boas Práticas SQL em Banco Relacional para Desenvolvedores
TDC2016 Boas Práticas SQL em Banco Relacional para DesenvolvedoresTDC2016 Boas Práticas SQL em Banco Relacional para Desenvolvedores
TDC2016 Boas Práticas SQL em Banco Relacional para DesenvolvedoresFernando Franquini
 
Criando sua própria linguagem de programação
Criando sua própria linguagem de programaçãoCriando sua própria linguagem de programação
Criando sua própria linguagem de programaçãoronaldoferraz
 
Programação Orientada a Testes
Programação Orientada a TestesProgramação Orientada a Testes
Programação Orientada a TestesGregorio Melo
 
Boas práticas de Automação de Testes
Boas práticas de Automação de TestesBoas práticas de Automação de Testes
Boas práticas de Automação de TestesCamilo Ribeiro
 
Slide curso metasploit
Slide curso metasploitSlide curso metasploit
Slide curso metasploitRoberto Soares
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitDiego Tremper
 
Grails parte 1 - introdução
Grails   parte 1 - introduçãoGrails   parte 1 - introdução
Grails parte 1 - introduçãoJosino Rodrigues
 
TDD - Prática com RSpec
TDD - Prática com RSpecTDD - Prática com RSpec
TDD - Prática com RSpecEduardo Mendes
 
Escrevendo códigos php seguros
Escrevendo códigos php segurosEscrevendo códigos php seguros
Escrevendo códigos php segurosDouglas V. Pasqua
 
Alg aula 08 - modularizacao
Alg   aula 08 - modularizacaoAlg   aula 08 - modularizacao
Alg aula 08 - modularizacaoThalles Anderson
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitDiego Tremper
 

Semelhante a Testes automatizados de software (20)

Introdução aos testes unitários
Introdução aos testes unitáriosIntrodução aos testes unitários
Introdução aos testes unitários
 
Design de código: princípios e práticas para ter um código sustentável
Design de código: princípios e práticas para ter um código sustentávelDesign de código: princípios e práticas para ter um código sustentável
Design de código: princípios e práticas para ter um código sustentável
 
Testes automatizados
Testes automatizadosTestes automatizados
Testes automatizados
 
TDC2016 Boas Práticas SQL em Banco Relacional para Desenvolvedores
TDC2016 Boas Práticas SQL em Banco Relacional para DesenvolvedoresTDC2016 Boas Práticas SQL em Banco Relacional para Desenvolvedores
TDC2016 Boas Práticas SQL em Banco Relacional para Desenvolvedores
 
Criando sua própria linguagem de programação
Criando sua própria linguagem de programaçãoCriando sua própria linguagem de programação
Criando sua própria linguagem de programação
 
Ganhando tempo com casos de testes
Ganhando tempo com casos de testesGanhando tempo com casos de testes
Ganhando tempo com casos de testes
 
Programação Orientada a Testes
Programação Orientada a TestesProgramação Orientada a Testes
Programação Orientada a Testes
 
Código Limpo
Código LimpoCódigo Limpo
Código Limpo
 
PowerShell
PowerShellPowerShell
PowerShell
 
Boas práticas de Automação de Testes
Boas práticas de Automação de TestesBoas práticas de Automação de Testes
Boas práticas de Automação de Testes
 
Object Oriented Programming
Object Oriented ProgrammingObject Oriented Programming
Object Oriented Programming
 
Slide curso metasploit
Slide curso metasploitSlide curso metasploit
Slide curso metasploit
 
Minicurso Ruby on Rails
Minicurso Ruby on RailsMinicurso Ruby on Rails
Minicurso Ruby on Rails
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnit
 
Grails parte 1 - introdução
Grails   parte 1 - introduçãoGrails   parte 1 - introdução
Grails parte 1 - introdução
 
TDD - Prática com RSpec
TDD - Prática com RSpecTDD - Prática com RSpec
TDD - Prática com RSpec
 
Escrevendo códigos php seguros
Escrevendo códigos php segurosEscrevendo códigos php seguros
Escrevendo códigos php seguros
 
Alg aula 08 - modularizacao
Alg   aula 08 - modularizacaoAlg   aula 08 - modularizacao
Alg aula 08 - modularizacao
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnit
 
Visualg
VisualgVisualg
Visualg
 

Mais de Tiago Albineli Motta

Challenges and research for a real-time recommendation at OLX
Challenges and research for a real-time recommendation at OLXChallenges and research for a real-time recommendation at OLX
Challenges and research for a real-time recommendation at OLXTiago Albineli Motta
 
Inteligência Artificial: Da ciência da computação à ciência de dados
Inteligência Artificial: Da ciência da computação à ciência de dadosInteligência Artificial: Da ciência da computação à ciência de dados
Inteligência Artificial: Da ciência da computação à ciência de dadosTiago Albineli Motta
 
Machine Learning no dia a dia do desenvolvedor (Atualizado)
Machine Learning no dia a dia do desenvolvedor (Atualizado)Machine Learning no dia a dia do desenvolvedor (Atualizado)
Machine Learning no dia a dia do desenvolvedor (Atualizado)Tiago Albineli Motta
 
Machine Learning no dia a dia do desenvolvedor
Machine Learning no dia a dia do desenvolvedorMachine Learning no dia a dia do desenvolvedor
Machine Learning no dia a dia do desenvolvedorTiago Albineli Motta
 
Machine Learning e experimentos online para evitar o cancelamento no GloboPlay
Machine Learning e experimentos online para evitar o cancelamento no GloboPlayMachine Learning e experimentos online para evitar o cancelamento no GloboPlay
Machine Learning e experimentos online para evitar o cancelamento no GloboPlayTiago Albineli Motta
 
A ciência de dados por traz de sistemas de recomendação
A ciência de dados por traz de sistemas de recomendaçãoA ciência de dados por traz de sistemas de recomendação
A ciência de dados por traz de sistemas de recomendaçãoTiago Albineli Motta
 
Recomendação de ponta a ponta na Globo.com
Recomendação de ponta a ponta na Globo.comRecomendação de ponta a ponta na Globo.com
Recomendação de ponta a ponta na Globo.comTiago Albineli Motta
 

Mais de Tiago Albineli Motta (18)

Multi Armed Bandit
Multi Armed BanditMulti Armed Bandit
Multi Armed Bandit
 
Challenges and research for a real-time recommendation at OLX
Challenges and research for a real-time recommendation at OLXChallenges and research for a real-time recommendation at OLX
Challenges and research for a real-time recommendation at OLX
 
Inteligência Artificial: Da ciência da computação à ciência de dados
Inteligência Artificial: Da ciência da computação à ciência de dadosInteligência Artificial: Da ciência da computação à ciência de dados
Inteligência Artificial: Da ciência da computação à ciência de dados
 
Machine Learning no dia a dia do desenvolvedor (Atualizado)
Machine Learning no dia a dia do desenvolvedor (Atualizado)Machine Learning no dia a dia do desenvolvedor (Atualizado)
Machine Learning no dia a dia do desenvolvedor (Atualizado)
 
Machine Learning no dia a dia do desenvolvedor
Machine Learning no dia a dia do desenvolvedorMachine Learning no dia a dia do desenvolvedor
Machine Learning no dia a dia do desenvolvedor
 
Experimentation anti patterns
Experimentation anti patternsExperimentation anti patterns
Experimentation anti patterns
 
Machine Learning e experimentos online para evitar o cancelamento no GloboPlay
Machine Learning e experimentos online para evitar o cancelamento no GloboPlayMachine Learning e experimentos online para evitar o cancelamento no GloboPlay
Machine Learning e experimentos online para evitar o cancelamento no GloboPlay
 
A ciência de dados por traz de sistemas de recomendação
A ciência de dados por traz de sistemas de recomendaçãoA ciência de dados por traz de sistemas de recomendação
A ciência de dados por traz de sistemas de recomendação
 
xCLiMF
xCLiMFxCLiMF
xCLiMF
 
Rastros digitais
Rastros digitaisRastros digitais
Rastros digitais
 
Big data
Big dataBig data
Big data
 
Recomendação de ponta a ponta na Globo.com
Recomendação de ponta a ponta na Globo.comRecomendação de ponta a ponta na Globo.com
Recomendação de ponta a ponta na Globo.com
 
Recomendação na Globo.com
Recomendação na Globo.comRecomendação na Globo.com
Recomendação na Globo.com
 
Otimizando seu projeto Rails
Otimizando seu projeto RailsOtimizando seu projeto Rails
Otimizando seu projeto Rails
 
Meta-programacao em python
Meta-programacao em pythonMeta-programacao em python
Meta-programacao em python
 
Redis na Prática
Redis na PráticaRedis na Prática
Redis na Prática
 
Dinamizando Sites Estáticos
Dinamizando Sites EstáticosDinamizando Sites Estáticos
Dinamizando Sites Estáticos
 
Escalando Sites com Nginx
Escalando Sites com NginxEscalando Sites com Nginx
Escalando Sites com Nginx
 

Testes automatizados de software

  • 1. Testes unitários e de integração Quando e Porque    
  • 2. Resumo Introdução Testes unitários Testes de integração Desenvolvimento outside-in Conclusão    
  • 3. O porque inicial... Tudo muda o tempo todo    
  • 4. Testes unitários Testando a menor unidade de código possível da forma mais isolada possível    
  • 5. Unitários: Exemplo inicial describe Jogador do let(:objetivo) { double } subject { Jogador.new(objetivo) } describe '#venceu?' do it "deveria ser true se completou objetivo" do objetivo.stub!(:completo?) { true } subject.venceu?.should be end end end    
  • 6. Unitários: Código testado class Jogador def initialize(objetivo) @objetivo = objetivo end def venceu? @objetivo.completo? end end    
  • 7. Unitários: Exemplo + completo describe Jogador do let(:objetivo) { double } let(:partida) { double } subject { Jogador.new(partida, objetivo) } describe '#venceu?' do #... it "deveria informar partida e jogador ao objetivo" do objetivo.should_receive(:completo?).with( subject, partida ) subject.venceu? end end end    
  • 8. Unitários: Código testado class Jogador def initialize(partida, objetivo) @objetivo = objetivo @partida = partida end def venceu? @objetivo.completo? self, @partida end end    
  • 9. Unitários: Ciclo do TDD Crie um teste Refatore Implemente a solução    
  • 10. Unitários: Prós Rápido de fazer e executar Incentiva o baixo acoplamento Facilita resolução de algoritmos    
  • 11. Unitários: Contras Falsa sensação de terminado Insegurança ao trocar contratos    
  • 12. Unitários: Exemplo de erro class Objetivo def completo?(jogador, partida) def terminado?(jogador, partida) #... end end    
  • 13. Testes de integração Testando para garantir que as classes e componentes estejam se integrando corretamente    
  • 14. Integração: Exemplo describe Jogador, "com objetivo de conquistar 24 territorios" do let(:objetivo) { Objetivos::Conquistar24Territorios } let(:partida) { Partida.new } subject { Jogador.create(partida: partida, objetivo: objetivo) } it "deveria vencer se tiver 24 territorios" do 24.times { subject.territorios << Territorio.new } subject.venceu?.should be end end    
  • 15. Integração: Modulo de Objetivos module Objetivos class Conquistar24Territorios def self.completo?(jogador, partida) jogador.territorios.count >= 24 end end end    
  • 16. Integração: End to end Comportamento do ponto de vista do usuário Exemplo: Dado que o jogador tem 23 territórios E o objetivo dele é conquistar 24 territórios Quando o jogador conquistar 1 território E finalizar a rodada Então Jogador vence a partida    
  • 17. Integração: Prós Garante o funcionamento do sistema Sensação de tarefa concluída    
  • 18. Integração: Contras Testes mais lentos Dificuldade de entender origem de erros    
  • 19. Como unir? Sensação de finalizado e segurança dos testes de integração end to end Facilidade, rapidez e desacoplamento proporcionados pelos testes unitários    
  • 20. Desenvolvimento Outside-in Definir caso de aceitação Preparar teste end-to-end Desenvolver funcionalidade com TDD Repetir isso infinitamente    
  • 21. Outside-in: Caso de aceitação Jogador com 4 exércitos em um território ataca território vizinho que possui apenas 1 exército e o conquista    
  • 22. Setup – inicialmente fake feature "Atacar" do scenario "territorio vizinho com 3 dados e conquistar" do dado_jogador_com_exercitos_no_pais(4, :brasil) dado_jogador_com_exercitos_no_pais(1, :argentina) end private def dado_jogador_com_exercitos_no_pais(exercitos, pais) end end    
  • 23. Acesso - falhando feature "Atacar" do before :each do @partida = Partida.create end scenario "territorio vizinho com 3 dados e conquistar" do jogador1 = dado_jogador_com_exercitos_no_pais(4, :brasil) jogador2 = dado_jogador_com_exercitos_no_pais(1, :argentina) dado_que_jogador_esta_logado(jogador1) end #... def dado_que_jogador_esta_logado(jogador) visit partida_path(@partida) end end    
  • 24. Acesso - funcionando models/partida.rb: class Partida < ActiveRecord::Base end config/routes.rb: War::Application.routes.draw do resources :partidas end controllers/partida_controller.rb: class PartidasController < ApplicationController def show end end Partidas/show.html.erb: <h1>Ok</h1>    
  • 25. Primeira interação - falhando scenario "territorio vizinho com 3 dados e conquistar" do #... dado_que_jogador_esta_logado(jogador1) quando_selecionar_territorio_que_vai_atacar(:brasil) end private #... def quando_selecionar_territorio_que_vai_atacar(pais) click_link pais.to_s end    
  • 26. Primeira interação - funcionando views/partidas.html.erb: <a href="#">brasil</a>    
  • 27. Mais interações - falhando scenario "territorio vizinho com 3 dados e conquistar" do #... quando_selecionar_territorio_que_vai_atacar(:brasil) quando_selecionar_territorio_atacado(:argentina) quando_confirmar_ataque end #... def quando_selecionar_territorio_atacado(pais) click_link pais.to_s end def quando_confirmar_ataque click_button 'Atacar' end    
  • 28. Mais interações - funcionando views/partidas.html.erb: <form> <a href="#">brasil</a> <a href="#">argentina</a> <input name="Atacar" value="Atacar" type="submit"/> </form>    
  • 29. Verficação - falhando scenario "territorio vizinho com 3 dados e conquistar" do #... quando_confirmar_ataque entao_territorio_eh_conquistado(:argentina) end #... def entao_territorio_eh_conquistado(pais) find('#mensagem').text.strip .should == "Territorio '#{pais}' conquistado" end    
  • 30. Verificação - funcionando views/partidas.html.erb: <form> <a href="#">brasil</a> <a href="#">argentina</a> <input name="Atacar" value="Atacar" type="submit"/> <div id="mensagem"> Territorio 'argentina' conquistado </div> </form>    
  • 31. O que temos até agora? Teste View Controller Model    
  • 32. Teste end-to-end ok Hora de ir mais fundo TDD a todo momento    
  • 33. Teste unitário do controller describe AtaquesController, 'POST' do it 'deveria redirecionar para a partida' do post :create, partida_id: 1, ataque: {} response.should redirect_to(partida_path(1)) end it 'deveria colocar mensagem de sucesso' do post :create, partida_id: 1, ataque: { pais_atacado: 'argentina' } flash[:mensagem]. should == "Territorio 'argentina' conquistado" end end    
  • 34. Controller de ataque class AtaquesController < ApplicationController def create pais = params[:ataque][:pais_atacado] flash[:mensagem] = "Territorio #{pais}' conquistado" redirect_to partida_path(params[:partida_id]) end end    
  • 35. View tem que mudar <div id="mensagem"><%= flash[:mensagem] %></div> <%= form_for :ataque, url: partida_ataques_url(@partida), method: :post do |f| %> <a href="#">brasil</a> <a href="#">argentina</a> <%= f.hidden_field 'pais_que_ataca' %> <%= f.hidden_field 'pais_atacado' %> <%= f.submit value: 'Atacar' %>   <% end %>  
  • 36. Javascript incluído var paisQueAtaca = $('#ataque_pais_que_ataca'); var paisAtacado = $('#ataque_pais_atacado'); var paisAtual = paisQueAtaca; var marcar = function(texto) { paisAtual.val(texto); } var trocaPaisAtual = function() { paisAtual = paisAtual == paisQueAtaca ? paisAtacado : paisQueAtaca; } $('a').click(function(e){ e.preventDefault(); marcar($(this).text()); trocaPaisAtual(); });    
  • 37. O que temos até agora? (2) Teste View Controller Model    
  • 38. Teste unitário do controller describe AtaquesController, 'POST' do let(:partida) { double(id: 1, executar_ataque: true) } before :each do Partida.stub!(:find) { partida } end #... it 'deveria executar ataque na partida' do params_ataque = {"meu_ataque" => true} partida.should_receive(:executar_ataque).with(params_ataque) post :create, partida_id: 1, ataque: params_ataque end end    
  • 39. Controller de ataque class AtaquesController < ApplicationController def create ataque = params[:ataque] partida = Partida.find params[:partida_id] partida.executar_ataque(ataque) pais = ataque[:pais_atacado] flash[:mensagem] = "Territorio '#{pais}' conquistado" redirect_to partida_path(partida) end end    
  • 40. Teste end-to-end falha $ rake spec:acceptance Failures: 1) Atacar territorio vizinho com 3 dados e conquistar Failure/Error: find('#mensagem').text.strip.should == "Territorio... Capybara::ElementNotFound: Unable to find css "#mensagem" Erro dificil de encontrar a origem!    
  • 41. Método não encontrado $ tail -f log/test.log Completed 500 Internal Server Error in 3ms undefined method `executar_ataque' for #<Partida:0xa5549c0> class Partida < ActiveRecord::Base def executar_ataque(attrs) end end    
  • 42. Um pouco de ousadia Que tal começar um outro caso de aceitação antes de terminar este?    
  • 43. Caso da derrota scenario "territorio vizinho com 3 dados e conquistar", js: true do dado_que_dados_vermelhos_estao_sortudos #... end scenario "territorio vizinho com 3 dados e nao conquistar", js: true do dado_que_dados_vermelhos_estao_azarentos #... end def dado_que_dados_vermelhos_estao_azarentos ENV["forcar_vitoria"] = "defesa" end def dados_que_dados_vermelhos_estao_sortudos ENV["forcar_vitoria"] = "ataque" end    
  • 44. Teste do controller context 'conquistando' do before :each do partida.stub!(:executar_ataque) { true } end it 'deveria colocar mensagem de sucesso' do post :create, partida_id: 1, ataque: { pais_atacado: 'argentina' } flash[:mensagem].should == "Territorio 'argentina' conquistado" end end context 'nao conquistando' do before :each do partida.stub!(:executar_ataque) { false } end it 'deveria colocar mensagem de insucesso' do post :create, partida_id: 1, ataque: { pais_atacado: 'argentina' } flash[:mensagem].should == "Territorio 'argentina' nao foi conquistado" end end    
  • 45. Controller de ataque class AtaquesController < ApplicationController def create ataque = params[:ataque] partida = Partida.find params[:partida_id] pais = ataque[:pais_atacado] if partida.executar_ataque(ataque) flash[:mensagem] = "Territorio '#{pais}' conquistado" else flash[:mensagem] = "Territorio '#{pais}' nao foi conquistado" end redirect_to partida_path(partida) end end    
  • 46. Metodo burro pro teste passar class Partida < ActiveRecord::Base def executar_ataque(attrs) ENV["forcar_vitoria"] != 'defesa' end end    
  • 47. O que temos até agora? (3) Teste View Controller Model    
  • 48. Integração com os models Dever de casa    
  • 49. Ciclo do outside-in Crie um teste end-to-end Crie um teste Refatore Refatore Implemente a solução    
  • 50. Conclusão Sempre guie o desenvolvimento por testes Tanto por testes de integração como unitários Combine-os em uma estratégia outside-in Siga sempre o mantra dos pequenos passos    
  • 51. Bibliografia Test Driven Development: By Example Kent Beck Working Effectively with Legacy Code Michael Feathers Growing Object-Oriented Software, Guided by Tests Steve Freeman