SlideShare una empresa de Scribd logo
1 de 74
Descargar para leer sin conexión
Test-driven Development no Rails
  Começando seu projeto com o pé direito

   2007, Nando Vieira – http://simplesideias.com.br
O que iremos ver?


    slides = Array.new
    slides << “O que é TDD?”
    slides << “Por que testar”
    slides << “Um pequeno exemplo”
    slides << “TDD no Rails”
    slides << “Fixtures”
    slides << “Testes unitários”
    slides << “Testes funcionais”
    slides << “Testes de integração”
    slides << “Mocks & Stubs”
    slides << “Dúvidas?”
O que é TDD?




   • Test-driven Development ou Desenvolvimento
     Guiado por Testes
   • Uma técnica de desenvolvimento de software
   • Ficou conhecida como um aspecto do XP
O que é TDD?



Kent Beck (TDD by Example, 2003):
  1. Escreva um teste que falhe antes de escrever
     qualquer código
  2. Elimine toda duplicação (refactoring)
  3. Resposta rápida a pequenas mudanças
  4. Escreva seus próprios testes
O que é TDD?



Processo:
                            2. Veja os testes falharem
     1. Escreva o teste



                            3. Escreva o código




     5. Refatore o código   4. Veja os testes passarem
Porque testar




“   Isso não me impediu de cometer a tresloucada loucura de
    publicar minha aplicação utilizando Rails 1.2.3 apenas um
    dia após o lançamento deles. Devo estar ficando doido
    mesmo.
    Ou isso ou tenho testes.
                        Thiago Arrais – Motiro, no Google Groups Ruby-Br
Porque testar




   Você:
    • escreverá códigos melhores
    • escreverá códigos mais rapidamente
    • identificará erros mais facilmente
    • não usará F5 nunca mais!
Um pequeno exemplo
test_calculator.rb
    class TestCalculator < Test::Unit::TestCase
      def setup
       @calc = Calculator.new
      end

     def teardown
       @calc = nil
      end

     def test_sum
       assert_equal(2, @calc.sum(1, 1), quot;1 + 1 = 2quot;)
      end

     def test_subtract
       assert_equal(1, @calc.subtract(2, 1), “2 - 1 = 1quot;)
      end

     def test_multiply
       assert_equal(4, @calc.multiply(2, 2), “2 x 2 = 4quot;)
      end

     def test_divide
       assert_equal(2, @calc.sum(4, 2), “4 / 2 = 2quot;)
       assert_raise(ZeroDivisionError) { @calc.divide(2, 0) }
      end
    end
Um pequeno exemplo
test_calculator.rb
    class TestCalculator < Test::Unit::TestCase
      def setup
       @calc = Calculator.new
      end

     def teardown
       @calc = nil
      end

     def test_sum
       assert_equal(2, @calc.sum(1, 1), quot;1 + 1 = 2quot;)
      end

     def test_subtract
       assert_equal(1, @calc.subtract(2, 1), “2 - 1 = 1quot;)
      end

     def test_multiply
       assert_equal(4, @calc.multiply(2, 2), “2 x 2 = 4quot;)
      end

     def test_divide
       assert_equal(2, @calc.sum(4, 2), “4 / 2 = 2quot;)
       assert_raise(ZeroDivisionError) { @calc.divide(2, 0) }
      end
    end
Um pequeno exemplo
test_calculator.rb
    class TestCalculator < Test::Unit::TestCase
      def setup
       @calc = Calculator.new
      end

     def teardown
       @calc = nil
      end

     def test_sum
       assert_equal(2, @calc.sum(1, 1), quot;1 + 1 = 2quot;)
      end

     def test_subtract
       assert_equal(1, @calc.subtract(2, 1), “2 - 1 = 1quot;)
      end

     def test_multiply
       assert_equal(4, @calc.multiply(2, 2), “2 x 2 = 4quot;)
      end

     def test_divide
       assert_equal(2, @calc.sum(4, 2), “4 / 2 = 2quot;)
       assert_raise(ZeroDivisionError) { @calc.divide(2, 0) }
      end
    end
Um pequeno exemplo
test_calculator.rb
    class TestCalculator < Test::Unit::TestCase
      def setup
       @calc = Calculator.new
      end

     def teardown
       @calc = nil
      end

     def test_sum
       assert_equal(2, @calc.sum(1, 1), quot;1 + 1 = 2quot;)
      end

     def test_subtract
       assert_equal(1, @calc.subtract(2, 1), “2 - 1 = 1quot;)
      end

     def test_multiply
       assert_equal(4, @calc.multiply(2, 2), “2 x 2 = 4quot;)
      end

     def test_divide
       assert_equal(2, @calc.sum(4, 2), “4 / 2 = 2quot;)
       assert_raise(ZeroDivisionError) { @calc.divide(2, 0) }
      end
    end
Um pequeno exemplo
test_calculator.rb
    class TestCalculator < Test::Unit::TestCase
      def setup
       @calc = Calculator.new
      end

     def teardown
       @calc = nil
      end

     def test_sum
       assert_equal(2, @calc.sum(1, 1), quot;1 + 1 = 2quot;)
      end

     def test_subtract
       assert_equal(1, @calc.subtract(2, 1), “2 - 1 = 1quot;)
      end

     def test_multiply
       assert_equal(4, @calc.multiply(2, 2), “2 x 2 = 4quot;)
      end

     def test_divide
       assert_equal(2, @calc.sum(4, 2), “4 / 2 = 2quot;)
       assert_raise(ZeroDivisionError) { @calc.divide(2, 0) }
      end
    end
Um pequeno exemplo
test_calculator.rb
    class TestCalculator < Test::Unit::TestCase
      def setup
       @calc = Calculator.new
      end

     def teardown
       @calc = nil
      end

     def test_sum
       assert_equal(2, @calc.sum(1, 1), quot;1 + 1 = 2quot;)
      end

     def test_subtract
       assert_equal(1, @calc.subtract(2, 1), “2 - 1 = 1quot;)
      end

     def test_multiply
       assert_equal(4, @calc.multiply(2, 2), “2 x 2 = 4quot;)
      end

     def test_divide
       assert_equal(2, @calc.sum(4, 2), “4 / 2 = 2quot;)
       assert_raise(ZeroDivisionError) { @calc.divide(2, 0) }
      end
    end
Um pequeno exemplo
calculator.rb
    class Calculator
      def sum(n1, n2)
       n1 + n2
      end

     def subtract(n1, n2)
       n1 - n2
      end

     def multiply(n1, n2)
       n1 * n2
      end

     def divide(n1, n2)
       n1 / n2
      end
    end
Um pequeno exemplo
calculator.rb

                            execute os testes:
    class Calculator
      def sum(n1, n2)
       n1 + n2
      end

     def subtract(n1, n2)
       n1 - n2
      end

     def multiply(n1, n2)
       n1 * n2
      end

     def divide(n1, n2)
       n1 / n2
      end
    end
Um pequeno exemplo
calculator.rb

                            execute os testes: todos eles devem falhar
    class Calculator
      def sum(n1, n2)
       n1 + n2              $~ ruby test_calculator.rb
      end
                            Loaded suite test
     def subtract(n1, n2)   Started
       n1 - n2
                            EEEE
      end
                            Finished in 0.0 seconds.
     def multiply(n1, n2)
                              1) Error:
       n1 * n2
      end
                            test_divide(TestCalculator):
     def divide(n1, n2)     NameError: uninitialized constant TestCalculator::Calculator
       n1 / n2
                                 test.rb:24:in `setup'
      end
    end                       ...
                            4 tests, 0 assertions, 0 failures, 4 errors
Um pequeno exemplo
calculator.rb

                            execute os testes: todos eles devem falhar
    class Calculator
      def sum(n1, n2)
       n1 + n2              $~ ruby test_calculator.rb
      end
                            Loaded suite test
     def subtract(n1, n2)   Started
       n1 - n2
                            EEEE
      end
                            Finished in 0.0 seconds.
     def multiply(n1, n2)
                              1) Error:
       n1 * n2
      end
                            test_divide(TestCalculator):
     def divide(n1, n2)     NameError: uninitialized constant TestCalculator::Calculator
       n1 / n2
                                 test.rb:24:in `setup'
      end
    end                       ...
                            4 tests, 0 assertions, 0 failures, 4 errors


                                      4 erros: nosso código não passou no teste
Um pequeno exemplo
calculator.rb

                            escreva o primeiro
    class Calculator
      def sum(n1, n2)
                            método:
       n1 + n2
      end

     def subtract(n1, n2)
       n1 - n2
      end

     def multiply(n1, n2)
       n1 * n2
      end

     def divide(n1, n2)
       n1 / n2
      end
    end
Um pequeno exemplo
calculator.rb

                            escreva o primeiro método: rode os testes
    class Calculator
      def sum(n1, n2)
       n1 + n2              $~ ruby test_calculator.rb
      end
                            Loaded suite test
     def subtract(n1, n2)   Started
       n1 - n2
                            EEE.
      end
                            Finished in 0.0 seconds.
     def multiply(n1, n2)
                              1) Error:
       n1 * n2
      end
                            test_divide(TestCalculator):
     def divide(n1, n2)     NoMethodError: undefined method `divide' for #<Calculator:
       n1 / n2
                            0x2e2069c>
      end
                                 test.rb:44:in `test_divide‘
    end

                             ...
                            4 tests, 1 assertions, 0 failures, 3 errors
Um pequeno exemplo
calculator.rb

                            escreva o primeiro método: rode os testes
    class Calculator
      def sum(n1, n2)
       n1 + n2              $~ ruby test_calculator.rb
      end
                            Loaded suite test
     def subtract(n1, n2)   Started
       n1 - n2
                            EEE.
      end
                            Finished in 0.0 seconds.
     def multiply(n1, n2)
                              1) Error:
       n1 * n2
      end
                            test_divide(TestCalculator):
     def divide(n1, n2)     NoMethodError: undefined method `divide' for #<Calculator:
       n1 / n2
                            0x2e2069c>
      end
                                 test.rb:44:in `test_divide‘
    end

                             ...
                            4 tests, 1 assertions, 0 failures, 3 errors



                            1 asserção: nosso código passou no teste
Um pequeno exemplo
calculator.rb

                            escreva o método
    class Calculator
      def sum(n1, n2)
                            seguinte:
       n1 + n2
      end

     def subtract(n1, n2)
       n2 - n1
      end

     def multiply(n1, n2)
       n1 * n2
      end

     def divide(n1, n2)
       n1 / n2
      end
    end
Um pequeno exemplo
calculator.rb

                            escreva o método seguinte: rode os testes
    class Calculator
      def sum(n1, n2)
       n1 + n2              $~ ruby test_calculator.rb
      end
                            Loaded suite test
     def subtract(n1, n2)   Started
       n2 - n1
                            EF.E
      end
                            Finished in 0.0 seconds.
     def multiply(n1, n2)
                                1) Failure:
       n1 * n2
      end
                            test_subtract(TestCalculator) [test.rb:35]:
     def divide(n1, n2)     2 - 1 = 1.
       n1 / n2
                            <1> expected but was
      end
    end                     <-1>.
                             ...
                            4 tests, 1 assertions, 1 failures, 2 errors
Um pequeno exemplo
calculator.rb

                            escreva o método seguinte: rode os testes
    class Calculator
      def sum(n1, n2)
       n1 + n2              $~ ruby test_calculator.rb
      end
                            Loaded suite test
     def subtract(n1, n2)   Started
       n2 - n1
                            EF.E
      end
                            Finished in 0.0 seconds.
     def multiply(n1, n2)
                                1) Failure:
       n1 * n2
      end
                            test_subtract(TestCalculator) [test.rb:35]:
     def divide(n1, n2)     2 - 1 = 1.
       n1 / n2
                            <1> expected but was
      end
    end                     <-1>.
                             ...
                            4 tests, 1 assertions, 1 failures, 2 errors


                            1 falha: nosso código não passou no teste
Um pequeno exemplo
calculator.rb

                            escreva o método seguinte: rode os testes
    class Calculator
      def sum(n1, n2)
       n1 + n2              $~ ruby test_calculator.rb
      end
                            Loaded suite test
     def subtract(n1, n2)   Started
       n2 - n1
                            EF.E
      end
                            Finished in 0.0 seconds.
     def multiply(n1, n2)
                                1) Failure:
       n1 * n2
      end
                            test_subtract(TestCalculator) [test.rb:35]:
     def divide(n1, n2)     2 - 1 = 1.
       n1 / n2
                            <1> expected but was
      end
    end                     <-1>.
                             ...
                            4 tests, 1 assertions, 1 failures, 2 errors


                            1 falha: nosso código não passou no teste
                            devia ser n1 - n2
Um pequeno exemplo
calculator.rb

                            corrija o método que falhou:
    class Calculator
      def sum(n1, n2)
       n1 + n2
      end

     def subtract(n1, n2)
       n1 - n2
      end

     def multiply(n1, n2)
       n1 * n2
      end

     def divide(n1, n2)
       n1 / n2
      end
    end
Um pequeno exemplo
calculator.rb

                            corrija o método que falhou: rode os testes
    class Calculator
      def sum(n1, n2)
       n1 + n2              $~ ruby test_calculator.rb
      end
                            Loaded suite test
     def subtract(n1, n2)   Started
       n1 - n2
                            E..E
      end
                            Finished in 0.0 seconds.
     def multiply(n1, n2)
                              1) Error:
       n1 * n2
      end
                            test_divide(TestCalculator):
     def divide(n1, n2)     NoMethodError: undefined method `divide' for #<Calculator:
       n1 / n2
                            0x2e2069c>
      end
                                 test.rb:44:in `test_divide‘
    end

                             ...
                            4 tests, 2 assertions, 0 failures, 2 errors
Um pequeno exemplo
calculator.rb

                            corrija o método que falhou: rode os testes
    class Calculator
      def sum(n1, n2)
       n1 + n2              $~ ruby test_calculator.rb
      end
                            Loaded suite test
     def subtract(n1, n2)   Started
       n1 - n2
                            E..E
      end
                            Finished in 0.0 seconds.
     def multiply(n1, n2)
                              1) Error:
       n1 * n2
      end
                            test_divide(TestCalculator):
     def divide(n1, n2)     NoMethodError: undefined method `divide' for #<Calculator:
       n1 / n2
                            0x2e2069c>
      end
                                 test.rb:44:in `test_divide‘
    end

                             ...
                            4 tests, 2 assertions, 0 failures, 2 errors



                            2 asserções: nosso código passou no teste
Um pequeno exemplo
calculator.rb

                            continue o processo:
    class Calculator
      def sum(n1, n2)
       n1 + n2
      end

     def subtract(n1, n2)
       n1 - n2
      end

     def multiply(n1, n2)
       n1 * n2
      end

     def divide(n1, n2)
       n1 / n2
      end
    end
Um pequeno exemplo
calculator.rb

                            continue o processo: execute os testes
    class Calculator
      def sum(n1, n2)
       n1 + n2              $~ ruby test_calculator.rb
      end
                            ...
     def subtract(n1, n2)   4 tests, 3 assertions, 0 failures, 1 errors
       n1 - n2
      end

     def multiply(n1, n2)
       n1 * n2
      end

     def divide(n1, n2)
       n1 / n2
      end
    end
Um pequeno exemplo
calculator.rb

                            continue o processo: execute os testes
    class Calculator
      def sum(n1, n2)
       n1 + n2              $~ ruby test_calculator.rb
      end
                            ...
     def subtract(n1, n2)   4 tests, 3 assertions, 0 failures, 1 errors
       n1 - n2
      end

     def multiply(n1, n2)
                                                         só mais um: ufa!
       n1 * n2
      end

     def divide(n1, n2)
       n1 / n2
      end
    end
Um pequeno exemplo
calculator.rb

                            escreva o último método:
    class Calculator
      def sum(n1, n2)
       n1 + n2
      end

     def subtract(n1, n2)
       n1 - n2
      end

     def multiply(n1, n2)
       n1 * n2
      end

     def divide(n1, n2)
       n1 / n2
      end
    end
Um pequeno exemplo
calculator.rb

                            escreva o último método: execute os testes
    class Calculator
      def sum(n1, n2)
       n1 + n2              $~ ruby test_calculator.rb
      end
                            Loaded suite test
     def subtract(n1, n2)   Started
       n1 - n2
                            ....
      end
                            Finished in 0.0 seconds.
     def multiply(n1, n2)
       n1 * n2
      end
                            4 tests, 5 assertions, 0 failures, 0 errors
     def divide(n1, n2)
       n1 / n2
      end
    end
Um pequeno exemplo
calculator.rb

                            escreva o último método: execute os testes
    class Calculator
      def sum(n1, n2)
       n1 + n2              $~ ruby test_calculator.rb
      end
                            Loaded suite test
     def subtract(n1, n2)   Started
       n1 - n2
                            ....
      end
                            Finished in 0.0 seconds.
     def multiply(n1, n2)
       n1 * n2
      end
                            4 tests, 5 assertions, 0 failures, 0 errors
     def divide(n1, n2)
       n1 / n2
      end
                            5 asserções, nenhuma falha/erro: código perfeito!
    end
TDD no Rails


  • Testar uma aplicação no Rails é muito simples
  • Os testes ficam no diretório test
  • Os arquivos de testes são criados para você
  • Apenas um comando: rake test
  • Dados de testes: fixtures
  • Testes unitários, funcionais, integração e performance
  • Mocks & Stubs
Fixtures


  • Conteúdo inicial do modelo
  • Ficam sob o diretório test/fixtures
  • SQL, CSV ou YAML

                          Modelo Artist



                          Tabela artists



                        Fixture artists.yml
Fixtures
test/fixtures/artists.yml



    nofx:
     id: 1
     name: NOFX
     url: http://nofxofficialwebsite.com
     created_at: <%= Time.now.strftime(:db) %>

    millencolin:
     id: 2
     name: Millencolin
     url: http://millencolin.com
     created_at: <%= 3.days.ago.strftime(:db) %>
Testes unitários


  • Testes unitários validam modelos
  • Ficam sob o diretório test/unit
  • Arquivo gerado pelo Rails: <model>_test.rb



                   script/generate model Artist


                      test/unit/artist_test.rb
Testes unitários
test/unit/artist_test.rb



    require File.dirname(__FILE__) + '/../test_helper'

    class ArtistTest < Test::Unit::TestCase
      fixtures :artists

     # Replace this with your real tests.
     def test_truth
       assert true
     end
    end
Testes unitários
test/unit/artist_test.rb


    require File.dirname(__FILE__) + '/../test_helper'

    class ArtistTest < Test::Unit::TestCase
      fixtures :artists

       def test_should_require_name
        artist = create(:name => nil)
        assert_not_nil artist.errors.on(:name), quot;:name should have had an errorquot;
        assert !artist.valid?, quot;artist should be invalidquot;
       end

     private
       def create(options={})
        Artist.create({
          :name => 'Death Cab For Cutie',
          :url => 'http://deathcabforcutie.com'
        }.merge(options))
       end
    end
Testes unitários
app/models/artist.rb


                                        execute os testes:
    class Artist < ActiveRecord::Base
    end
Testes unitários
app/models/artist.rb


                                        execute os testes: rake test:units
    class Artist < ActiveRecord::Base
    end                                 $~ rake test:units
                                        Loaded suite test
                                        Started
                                        F
                                        Finished in 0.094 seconds.

                                          1) Failure:
                                        test_should_require_name(ArtistTest) [./test/
                                        unit/artist_test.rb:8]:
                                        :name should have had an error.
                                        <nil> expected to not be nil.

                                        1 tests, 1 assertions, 1 failures, 0 errors
Testes unitários
app/models/artist.rb


                                        execute os testes: rake test:units
    class Artist < ActiveRecord::Base
    end                                 $~ rake test:units
                                        Loaded suite test
                                        Started
                                        F
                                        Finished in 0.094 seconds.

                                          1) Failure:
                                        test_should_require_name(ArtistTest) [./test/
                                        unit/artist_test.rb:8]:
                                        :name should have had an error.
                                        <nil> expected to not be nil.

                                        1 tests, 1 assertions, 1 failures, 0 errors



                                                  o teste falhou: era esperado!
Testes unitários
app/models/artist.rb


                                        adicione a validação:
    class Artist < ActiveRecord::Base
      validates_presence_of :name
    end
Testes unitários
app/models/artist.rb


                                        adicione a validação: execute os testes
    class Artist < ActiveRecord::Base
      validates_presence_of :name       $~ rake test:units
    end
                                        Loaded suite test
                                        Started
                                        .
                                        Finished in 0.062 seconds.

                                        1 tests, 2 assertions, 0 failures, 0 errors
Testes unitários
app/models/artist.rb


                                        adicione a validação: execute os testes
    class Artist < ActiveRecord::Base
      validates_presence_of :name       $~ rake test:units
    end
                                        Loaded suite test
                                        Started
                                        .
                                        Finished in 0.062 seconds.

                                        1 tests, 2 assertions, 0 failures, 0 errors



                                                             nenhuma falha: voila!
Testes funcionais


  • Testes funcionais validam controles
  • Ficam sob o diretório test/functional
  • Template e/ou requisição
  • Arquivo gerado pelo Rails: <controller>_test.rb


                    script/generate controller artists


             test/functional/artists_controller_test.rb
Testes funcionais
test/functional/artists_controller_test.rb


    require File.dirname(__FILE__) + '/../test_helper‘
    require ‘artists_controller‘

    # Re-raise errors caught by the controller.
    class ArtistsController; def rescue_action(e) raise e end; end

    class ArtistsControllerTest < Test::Unit::TestCase
      def setup
       @controller = ArtistsController.new
       @request = ActionController::TestRequest.new
       @response = ActionController::TestResponse.new
      end

     # Replace this with your real tests.
     def test_truth
       assert true
     end
    end
Testes funcionais
test/functional/artists_controller_test.rb

...

class ArtistsControllerTest < Test::Unit::TestCase
  def setup
   @controller = ArtistsController.new
   @request = ActionController::TestRequest.new
   @response = ActionController::TestResponse.new
  end

  def test_index_page
   get index_path
   assert_response :success
   assert_template ‘index’

   assert_select ‘h1’, ‘Bands that sound like...’
   assert_select ‘form’, {:count => 1, :method} => ‘get’ do
    assert_select ‘input#name’, :count => 1
    assert_select ‘input[type=submit]’, :count => 1
   end
 end
end
Testes funcionais
test/functional/artists_controller_test.rb

...

class ArtistsControllerTest < Test::Unit::TestCase
  def setup
   @controller = ArtistsController.new
   @request = ActionController::TestRequest.new
   @response = ActionController::TestResponse.new
  end

  def test_index_page
   get index_path
   assert_response :success
                                             requisição: verificando a resposta
   assert_template ‘index’

   assert_select ‘h1’, ‘Bands that sound like...’
   assert_select ‘form’, {:count => 1, :method} => ‘get’ do
    assert_select ‘input#name’, :count => 1
                                                              template: verificando o markup
    assert_select ‘input[type=submit]’, :count => 1
   end
 end
end
Testes funcionais


                                                    execute os testes:
~$ rake test:functionals
Loaded suite test
Started
E
Finished in 0.094 seconds.


    1) Error:
test_index_page(ArtistsControllerTest):
ActionController::UnknownAction: No action responded to index
     ...
     ./test/functional/artists_controller_test.rb:15:in `test_index_page'


1 tests, 0 assertions, 0 failures, 1 errors
Testes funcionais


                                                    execute os testes: eles devem falhar
~$ rake test:functionals
Loaded suite test
Started
E
Finished in 0.094 seconds.


    1) Error:
test_index_page(ArtistsControllerTest):
ActionController::UnknownAction: No action responded to index
     ...
     ./test/functional/artists_controller_test.rb:15:in `test_index_page'


1 tests, 0 assertions, 0 failures, 1 errors
Testes funcionais


                                                    execute os testes: eles devem falhar
~$ rake test:functionals
Loaded suite test
Started
E
Finished in 0.094 seconds.


    1) Error:
test_index_page(ArtistsControllerTest):
ActionController::UnknownAction: No action responded to index
     ...
     ./test/functional/artists_controller_test.rb:15:in `test_index_page'


                                                      1 erro: ele já era esperado
1 tests, 0 assertions, 0 failures, 1 errors
Testes funcionais


                                                    execute os testes: eles devem falhar
~$ rake test:functionals
Loaded suite test
Started
E
Finished in 0.094 seconds.

                                              action: nós ainda não a criamos
    1) Error:
test_index_page(ArtistsControllerTest):
ActionController::UnknownAction: No action responded to index
     ...
     ./test/functional/artists_controller_test.rb:15:in `test_index_page'


                                                      1 erro: ele já era esperado
1 tests, 0 assertions, 0 failures, 1 errors
Testes funcionais


                                                crie o template index.rhtml:
~$ rake test:functionals
Loaded suite test
Started
E
Finished in 0.094 seconds.


    1) Failure:
test_index_page(ArtistsControllerTest)
     [selector_assertions.rb:281:in `assert_select'
      ./test/functional/artists_controller_test.rb:19:in `test_index_page']:
Expected at least 1 elements, found 0.
<false> is not true.
1 tests, 3 assertions, 1 failures, 0 errors
Testes funcionais


                                                crie o template index.rhtml: execute os testes
~$ rake test:functionals
Loaded suite test
Started
E
Finished in 0.094 seconds.


    1) Failure:
test_index_page(ArtistsControllerTest)
     [selector_assertions.rb:281:in `assert_select'
      ./test/functional/artists_controller_test.rb:19:in `test_index_page']:
Expected at least 1 elements, found 0.
<false> is not true.
1 tests, 3 assertions, 1 failures, 0 errors
Testes funcionais


                                                crie o template index.rhtml: execute os testes
~$ rake test:functionals
Loaded suite test
Started
E
Finished in 0.094 seconds.


    1) Failure:
test_index_page(ArtistsControllerTest)
     [selector_assertions.rb:281:in `assert_select'
      ./test/functional/artists_controller_test.rb:19:in `test_index_page']:
Expected at least 1 elements, found 0.
<false> is not true.
                                                       1 erro: ele já era esperado
1 tests, 3 assertions, 1 failures, 0 errors
Testes funcionais


                                                crie o template index.rhtml: execute os testes
~$ rake test:functionals
Loaded suite test
Started
E
Finished in 0.094 seconds.


                             template: nenhum código HTML
    1) Failure:
test_index_page(ArtistsControllerTest)
     [selector_assertions.rb:281:in `assert_select'
      ./test/functional/artists_controller_test.rb:19:in `test_index_page']:
Expected at least 1 elements, found 0.
<false> is not true.
                                                       1 erro: ele já era esperado
1 tests, 3 assertions, 1 failures, 0 errors
Testes funcionais
app/views/artists/index.rhtml


                                               código HTML:
 <h1>Bands that sound like...</h1>
 <% form_tag 'view', {:method => :get} do %>
  <p>
    <%= text_field_tag :name %>
    <%= submit_tag ‘View' %>
  </p>
 <% end %>
Testes funcionais
app/views/artists/index.rhtml


                                               código HTML: execute os testes
 <h1>Bands that sound like...</h1>
 <% form_tag 'view', {:method => :get} do %>    ~$ rake test:functionals
  <p>
                                                Loaded suite test
    <%= text_field_tag :name %>
                                                Started
    <%= submit_tag ‘View' %>
                                                .
  </p>
                                                Finished in 0.094 seconds.
 <% end %>
                                                1 tests, 9 assertions, 0 failures, 0 errors
Testes funcionais
app/views/artists/index.rhtml


                                               código HTML: execute os testes
 <h1>Bands that sound like...</h1>
 <% form_tag 'view', {:method => :get} do %>    ~$ rake test:functionals
  <p>
                                                Loaded suite test
    <%= text_field_tag :name %>
                                                Started
    <%= submit_tag ‘View' %>
                                                .
  </p>
                                                Finished in 0.094 seconds.
 <% end %>
                                                1 tests, 9 assertions, 0 failures, 0 errors



                                                    yep: tudo certo!
                                                    erros: nenhum para contar história
Testes de integração


  • Testes de integração validam (duh) a integração entre
    diferentes controllers
  • Ficam sob o diretório test/integration
  • Rails não gera arquivo automaticamente: você escolhe!


          script/generate integration_test artist_stories


               test/integraton/artist_stories_test.rb
Testes de integração
test/integration/artist_stories_test.rb



    require File.dirname(__FILE__) + '/../test_helper'

    class ArtistStoriesTest < ActionController::IntegrationTest
      # fixtures :your, :models

     # Replace this with your real tests.
     def test_truth
       assert true
     end
    end
Testes de integração
test/integration/artist_stories_test.rb


    require File.dirname(__FILE__) + '/../test_helper'

    class ArtistStoriesTest < ActionController::IntegrationTest
      fixtures :artists, :albums

      def test_user_viewing_artist_and_album
       # user accessing index page
       get quot;/quot;
       assert_response :success
       assert_template quot;indexquot;

        # searching for an artist
        get artist_search_path(artists(:millencolin).slug)
        assert_response :redirect
        assert_redirected_to quot;/artists/#{artists(:millencolin).slug}quot;

       # viewing album quot;life on a platequot;
       get album_path(albums(:life_on_a_plate))
       assert_response :success
       assert_template quot;viewquot;
     end
    end
Testes de integração
test/integration/artist_stories_test.rb


    require File.dirname(__FILE__) + '/../test_helper'

    class ArtistStoriesTest < ActionController::IntegrationTest
      fixtures :artists, :albums

      def test_user_viewing_artist_and_album
       # user accessing index page
       get quot;/quot;
                                                   controller: /
       assert_response :success
       assert_template quot;indexquot;

        # searching for an artist
        get artist_search_path(artists(:millencolin).slug)
        assert_response :redirect                                         controller: /artists/search
        assert_redirected_to quot;/artists/#{artists(:millencolin).slug}quot;

       # viewing album quot;life on a platequot;
       get album_path(albums(:life_on_a_plate))
       assert_response :success
                                                                   controller: /albums/
       assert_template quot;viewquot;
     end
    end
Testes de integração


  • Testes funcionais em um nível mais alto: DSL
  • Leitura mais fácil, impossível!
  • Use o método open_session


                       open_session do |session|
                        # Do everything you need!
                       end
Testes de integração
test/integration/artist_stories_test.rb

 class ArtistStoriesTest < ActionController::IntegrationTest
   fixtures :artists, :albums

  def test_artist_story
   artist = artists(:millencolin)

   user = new_session
   user.search_artist artist
   user.view_album artist.albums.first
  end


  private
   def new_session
     open_session do |session|
       def session.search_artist(artist)
         get search_artist(artist.name)
         assert_response :redirect
         assert_redirected_to artist_path(artist.slug)
       end

       def session.view_album(album)
        get album_path(album.slug)
        assert_response :success
        assert_template 'view'
       end
     end
    end
 end
Testes de integração
test/integration/artist_stories_test.rb

 class ArtistStoriesTest < ActionController::IntegrationTest
   fixtures :artists, :albums

  def test_artist_story
   artist = artists(:millencolin)

   user = new_session
                                                      user = new_session
   user.search_artist artist
                                                      user.search_artist artist
   user.view_album artist.albums.first
  end
                                                      user.view_album artist.albums.first
  private
   def new_session
     open_session do |session|
       def session.search_artist(artist)
         get search_artist(artist.name)
         assert_response :redirect
         assert_redirected_to artist_path(artist.slug)
       end

       def session.view_album(album)
        get album_path(album.slug)
        assert_response :success
        assert_template 'view'
       end
     end
    end
 end
Testes de integração
test/integration/artist_stories_test.rb

 class ArtistStoriesTest < ActionController::IntegrationTest
   fixtures :artists, :albums

  def test_artist_story
   artist = artists(:millencolin)

   user = new_session
                                                      user = new_session
   user.search_artist artist
                                                      user.search_artist artist
   user.view_album artist.albums.first
  end
                                                      user.view_album artist.albums.first
  private
   def new_session
     open_session do |session|
       def session.search_artist(artist)
         get search_artist(artist.name)
                                                               melhor, impossível!
         assert_response :redirect
         assert_redirected_to artist_path(artist.slug)
       end

       def session.view_album(album)
        get album_path(album.slug)
        assert_response :success
        assert_template 'view'
       end
     end
    end
 end
Mocks & Stubs


  • Códigos que eliminam o acesso a um recurso
  • Ficam sob o diretório test/mocks/test
  • Deve ter o mesmo nome do arquivo e estrutura da
    classe/módulo que você quer substituir


                RAILS_ROOT/lib/launch_missile.rb


          test/mocks/<RAILS_ENV>/launch_missile.rb
Mocks & Stubs
lib/feed.rb




 require ‘open-uri’

 class Feed
   def load(url)
    open URI.parse(url).read
   end
 end
Mocks & Stubs
lib/feed.rb




 require ‘open-uri’

 class Feed
   def load(url)
    open URI.parse(url).read
   end
 end
          não é o ideal:
           a) pode ser lento;
           b) pode não estar disponível;
           c) imagine se fosse transação de pagamento!
Mocks & Stubs
test/mocks/test/feed.rb




 require ‘open-uri’

 class Feed
   def load(url)
    File.new(“#{RAILS_ROOT}/test/fixtures/feed.xml”).read
   end
 end
Mocks & Stubs
test/mocks/test/feed.rb




 require ‘open-uri’

 class Feed
   def load(url)
    File.new(“#{RAILS_ROOT}/test/fixtures/feed.xml”).read
   end
 end
           muito mais fácil e rápido: faça quantos pagamentos quiser!
Dúvidas?

Más contenido relacionado

Similar a Test-Driven Development with Rails

Test-driven Development no Rails
Test-driven Development no RailsTest-driven Development no Rails
Test-driven Development no Railselliando dias
 
Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8Frédéric Delorme
 
關於測試,我說的其實是......
關於測試,我說的其實是......關於測試,我說的其實是......
關於測試,我說的其實是......hugo lu
 
Testing orm based code
Testing orm based codeTesting orm based code
Testing orm based codeViktor Turskyi
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven DevelopmentSheeju Alex
 
Java script – basic auroskills (2)
Java script – basic   auroskills (2)Java script – basic   auroskills (2)
Java script – basic auroskills (2)BoneyGawande
 
Tdd for BT E2E test community
Tdd for BT E2E test communityTdd for BT E2E test community
Tdd for BT E2E test communityKerry Buckley
 
Ruby Metaprogramming
Ruby MetaprogrammingRuby Metaprogramming
Ruby MetaprogrammingThaichor Seng
 
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...Rodolfo Carvalho
 
Fault Tolerant Clustering (IEEE Services 2012)
Fault Tolerant Clustering (IEEE Services 2012)Fault Tolerant Clustering (IEEE Services 2012)
Fault Tolerant Clustering (IEEE Services 2012)Weiwei Chen
 
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)Igalia
 
Dynamic Analysis - SCOTCH: Improving Test-to-Code Traceability using Slicing ...
Dynamic Analysis - SCOTCH: Improving Test-to-Code Traceability using Slicing ...Dynamic Analysis - SCOTCH: Improving Test-to-Code Traceability using Slicing ...
Dynamic Analysis - SCOTCH: Improving Test-to-Code Traceability using Slicing ...ICSM 2011
 
Background Jobs - Com BackgrounDRb
Background Jobs - Com BackgrounDRbBackground Jobs - Com BackgrounDRb
Background Jobs - Com BackgrounDRbJuan Maiz
 
OPM Recipe designer notes
OPM Recipe designer notesOPM Recipe designer notes
OPM Recipe designer notested-xu
 

Similar a Test-Driven Development with Rails (20)

Test-driven Development no Rails
Test-driven Development no RailsTest-driven Development no Rails
Test-driven Development no Rails
 
TDD, BDD and mocks
TDD, BDD and mocksTDD, BDD and mocks
TDD, BDD and mocks
 
Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8Bdd for-dso-1227123516572504-8
Bdd for-dso-1227123516572504-8
 
關於測試,我說的其實是......
關於測試,我說的其實是......關於測試,我說的其實是......
關於測試,我說的其實是......
 
Deixe o teste infectar você
Deixe o teste infectar vocêDeixe o teste infectar você
Deixe o teste infectar você
 
Testing orm based code
Testing orm based codeTesting orm based code
Testing orm based code
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
Java script – basic auroskills (2)
Java script – basic   auroskills (2)Java script – basic   auroskills (2)
Java script – basic auroskills (2)
 
Tdd for BT E2E test community
Tdd for BT E2E test communityTdd for BT E2E test community
Tdd for BT E2E test community
 
How to fake_properly
How to fake_properlyHow to fake_properly
How to fake_properly
 
Ruby Metaprogramming
Ruby MetaprogrammingRuby Metaprogramming
Ruby Metaprogramming
 
PHPSpec BDD for PHP
PHPSpec BDD for PHPPHPSpec BDD for PHP
PHPSpec BDD for PHP
 
PerlTesting
PerlTestingPerlTesting
PerlTesting
 
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
 
Fault Tolerant Clustering (IEEE Services 2012)
Fault Tolerant Clustering (IEEE Services 2012)Fault Tolerant Clustering (IEEE Services 2012)
Fault Tolerant Clustering (IEEE Services 2012)
 
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)
 
Scala to assembly
Scala to assemblyScala to assembly
Scala to assembly
 
Dynamic Analysis - SCOTCH: Improving Test-to-Code Traceability using Slicing ...
Dynamic Analysis - SCOTCH: Improving Test-to-Code Traceability using Slicing ...Dynamic Analysis - SCOTCH: Improving Test-to-Code Traceability using Slicing ...
Dynamic Analysis - SCOTCH: Improving Test-to-Code Traceability using Slicing ...
 
Background Jobs - Com BackgrounDRb
Background Jobs - Com BackgrounDRbBackground Jobs - Com BackgrounDRb
Background Jobs - Com BackgrounDRb
 
OPM Recipe designer notes
OPM Recipe designer notesOPM Recipe designer notes
OPM Recipe designer notes
 

Más de Nando Vieira

Metaprogramming 101
Metaprogramming 101Metaprogramming 101
Metaprogramming 101Nando Vieira
 
A explosão do Node.js: JavaScript é o novo preto
A explosão do Node.js: JavaScript é o novo pretoA explosão do Node.js: JavaScript é o novo preto
A explosão do Node.js: JavaScript é o novo pretoNando Vieira
 
Presentta: usando Node.js na prática
Presentta: usando Node.js na práticaPresentta: usando Node.js na prática
Presentta: usando Node.js na práticaNando Vieira
 
Ruby Metaprogramming
Ruby MetaprogrammingRuby Metaprogramming
Ruby MetaprogrammingNando Vieira
 
Testando Rails apps com RSpec
Testando Rails apps com RSpecTestando Rails apps com RSpec
Testando Rails apps com RSpecNando Vieira
 
O que mudou no Ruby 1.9
O que mudou no Ruby 1.9O que mudou no Ruby 1.9
O que mudou no Ruby 1.9Nando Vieira
 
jQuery - Javascript para quem não sabe Javascript
jQuery - Javascript para quem não sabe JavascriptjQuery - Javascript para quem não sabe Javascript
jQuery - Javascript para quem não sabe JavascriptNando Vieira
 

Más de Nando Vieira (7)

Metaprogramming 101
Metaprogramming 101Metaprogramming 101
Metaprogramming 101
 
A explosão do Node.js: JavaScript é o novo preto
A explosão do Node.js: JavaScript é o novo pretoA explosão do Node.js: JavaScript é o novo preto
A explosão do Node.js: JavaScript é o novo preto
 
Presentta: usando Node.js na prática
Presentta: usando Node.js na práticaPresentta: usando Node.js na prática
Presentta: usando Node.js na prática
 
Ruby Metaprogramming
Ruby MetaprogrammingRuby Metaprogramming
Ruby Metaprogramming
 
Testando Rails apps com RSpec
Testando Rails apps com RSpecTestando Rails apps com RSpec
Testando Rails apps com RSpec
 
O que mudou no Ruby 1.9
O que mudou no Ruby 1.9O que mudou no Ruby 1.9
O que mudou no Ruby 1.9
 
jQuery - Javascript para quem não sabe Javascript
jQuery - Javascript para quem não sabe JavascriptjQuery - Javascript para quem não sabe Javascript
jQuery - Javascript para quem não sabe Javascript
 

Último

Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxBkGupta21
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 

Último (20)

Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptx
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 

Test-Driven Development with Rails

  • 1. Test-driven Development no Rails Começando seu projeto com o pé direito 2007, Nando Vieira – http://simplesideias.com.br
  • 2. O que iremos ver? slides = Array.new slides << “O que é TDD?” slides << “Por que testar” slides << “Um pequeno exemplo” slides << “TDD no Rails” slides << “Fixtures” slides << “Testes unitários” slides << “Testes funcionais” slides << “Testes de integração” slides << “Mocks & Stubs” slides << “Dúvidas?”
  • 3. O que é TDD? • Test-driven Development ou Desenvolvimento Guiado por Testes • Uma técnica de desenvolvimento de software • Ficou conhecida como um aspecto do XP
  • 4. O que é TDD? Kent Beck (TDD by Example, 2003): 1. Escreva um teste que falhe antes de escrever qualquer código 2. Elimine toda duplicação (refactoring) 3. Resposta rápida a pequenas mudanças 4. Escreva seus próprios testes
  • 5. O que é TDD? Processo: 2. Veja os testes falharem 1. Escreva o teste 3. Escreva o código 5. Refatore o código 4. Veja os testes passarem
  • 6. Porque testar “ Isso não me impediu de cometer a tresloucada loucura de publicar minha aplicação utilizando Rails 1.2.3 apenas um dia após o lançamento deles. Devo estar ficando doido mesmo. Ou isso ou tenho testes. Thiago Arrais – Motiro, no Google Groups Ruby-Br
  • 7. Porque testar Você: • escreverá códigos melhores • escreverá códigos mais rapidamente • identificará erros mais facilmente • não usará F5 nunca mais!
  • 8. Um pequeno exemplo test_calculator.rb class TestCalculator < Test::Unit::TestCase def setup @calc = Calculator.new end def teardown @calc = nil end def test_sum assert_equal(2, @calc.sum(1, 1), quot;1 + 1 = 2quot;) end def test_subtract assert_equal(1, @calc.subtract(2, 1), “2 - 1 = 1quot;) end def test_multiply assert_equal(4, @calc.multiply(2, 2), “2 x 2 = 4quot;) end def test_divide assert_equal(2, @calc.sum(4, 2), “4 / 2 = 2quot;) assert_raise(ZeroDivisionError) { @calc.divide(2, 0) } end end
  • 9. Um pequeno exemplo test_calculator.rb class TestCalculator < Test::Unit::TestCase def setup @calc = Calculator.new end def teardown @calc = nil end def test_sum assert_equal(2, @calc.sum(1, 1), quot;1 + 1 = 2quot;) end def test_subtract assert_equal(1, @calc.subtract(2, 1), “2 - 1 = 1quot;) end def test_multiply assert_equal(4, @calc.multiply(2, 2), “2 x 2 = 4quot;) end def test_divide assert_equal(2, @calc.sum(4, 2), “4 / 2 = 2quot;) assert_raise(ZeroDivisionError) { @calc.divide(2, 0) } end end
  • 10. Um pequeno exemplo test_calculator.rb class TestCalculator < Test::Unit::TestCase def setup @calc = Calculator.new end def teardown @calc = nil end def test_sum assert_equal(2, @calc.sum(1, 1), quot;1 + 1 = 2quot;) end def test_subtract assert_equal(1, @calc.subtract(2, 1), “2 - 1 = 1quot;) end def test_multiply assert_equal(4, @calc.multiply(2, 2), “2 x 2 = 4quot;) end def test_divide assert_equal(2, @calc.sum(4, 2), “4 / 2 = 2quot;) assert_raise(ZeroDivisionError) { @calc.divide(2, 0) } end end
  • 11. Um pequeno exemplo test_calculator.rb class TestCalculator < Test::Unit::TestCase def setup @calc = Calculator.new end def teardown @calc = nil end def test_sum assert_equal(2, @calc.sum(1, 1), quot;1 + 1 = 2quot;) end def test_subtract assert_equal(1, @calc.subtract(2, 1), “2 - 1 = 1quot;) end def test_multiply assert_equal(4, @calc.multiply(2, 2), “2 x 2 = 4quot;) end def test_divide assert_equal(2, @calc.sum(4, 2), “4 / 2 = 2quot;) assert_raise(ZeroDivisionError) { @calc.divide(2, 0) } end end
  • 12. Um pequeno exemplo test_calculator.rb class TestCalculator < Test::Unit::TestCase def setup @calc = Calculator.new end def teardown @calc = nil end def test_sum assert_equal(2, @calc.sum(1, 1), quot;1 + 1 = 2quot;) end def test_subtract assert_equal(1, @calc.subtract(2, 1), “2 - 1 = 1quot;) end def test_multiply assert_equal(4, @calc.multiply(2, 2), “2 x 2 = 4quot;) end def test_divide assert_equal(2, @calc.sum(4, 2), “4 / 2 = 2quot;) assert_raise(ZeroDivisionError) { @calc.divide(2, 0) } end end
  • 13. Um pequeno exemplo test_calculator.rb class TestCalculator < Test::Unit::TestCase def setup @calc = Calculator.new end def teardown @calc = nil end def test_sum assert_equal(2, @calc.sum(1, 1), quot;1 + 1 = 2quot;) end def test_subtract assert_equal(1, @calc.subtract(2, 1), “2 - 1 = 1quot;) end def test_multiply assert_equal(4, @calc.multiply(2, 2), “2 x 2 = 4quot;) end def test_divide assert_equal(2, @calc.sum(4, 2), “4 / 2 = 2quot;) assert_raise(ZeroDivisionError) { @calc.divide(2, 0) } end end
  • 14. Um pequeno exemplo calculator.rb class Calculator def sum(n1, n2) n1 + n2 end def subtract(n1, n2) n1 - n2 end def multiply(n1, n2) n1 * n2 end def divide(n1, n2) n1 / n2 end end
  • 15. Um pequeno exemplo calculator.rb execute os testes: class Calculator def sum(n1, n2) n1 + n2 end def subtract(n1, n2) n1 - n2 end def multiply(n1, n2) n1 * n2 end def divide(n1, n2) n1 / n2 end end
  • 16. Um pequeno exemplo calculator.rb execute os testes: todos eles devem falhar class Calculator def sum(n1, n2) n1 + n2 $~ ruby test_calculator.rb end Loaded suite test def subtract(n1, n2) Started n1 - n2 EEEE end Finished in 0.0 seconds. def multiply(n1, n2) 1) Error: n1 * n2 end test_divide(TestCalculator): def divide(n1, n2) NameError: uninitialized constant TestCalculator::Calculator n1 / n2 test.rb:24:in `setup' end end ... 4 tests, 0 assertions, 0 failures, 4 errors
  • 17. Um pequeno exemplo calculator.rb execute os testes: todos eles devem falhar class Calculator def sum(n1, n2) n1 + n2 $~ ruby test_calculator.rb end Loaded suite test def subtract(n1, n2) Started n1 - n2 EEEE end Finished in 0.0 seconds. def multiply(n1, n2) 1) Error: n1 * n2 end test_divide(TestCalculator): def divide(n1, n2) NameError: uninitialized constant TestCalculator::Calculator n1 / n2 test.rb:24:in `setup' end end ... 4 tests, 0 assertions, 0 failures, 4 errors 4 erros: nosso código não passou no teste
  • 18. Um pequeno exemplo calculator.rb escreva o primeiro class Calculator def sum(n1, n2) método: n1 + n2 end def subtract(n1, n2) n1 - n2 end def multiply(n1, n2) n1 * n2 end def divide(n1, n2) n1 / n2 end end
  • 19. Um pequeno exemplo calculator.rb escreva o primeiro método: rode os testes class Calculator def sum(n1, n2) n1 + n2 $~ ruby test_calculator.rb end Loaded suite test def subtract(n1, n2) Started n1 - n2 EEE. end Finished in 0.0 seconds. def multiply(n1, n2) 1) Error: n1 * n2 end test_divide(TestCalculator): def divide(n1, n2) NoMethodError: undefined method `divide' for #<Calculator: n1 / n2 0x2e2069c> end test.rb:44:in `test_divide‘ end ... 4 tests, 1 assertions, 0 failures, 3 errors
  • 20. Um pequeno exemplo calculator.rb escreva o primeiro método: rode os testes class Calculator def sum(n1, n2) n1 + n2 $~ ruby test_calculator.rb end Loaded suite test def subtract(n1, n2) Started n1 - n2 EEE. end Finished in 0.0 seconds. def multiply(n1, n2) 1) Error: n1 * n2 end test_divide(TestCalculator): def divide(n1, n2) NoMethodError: undefined method `divide' for #<Calculator: n1 / n2 0x2e2069c> end test.rb:44:in `test_divide‘ end ... 4 tests, 1 assertions, 0 failures, 3 errors 1 asserção: nosso código passou no teste
  • 21. Um pequeno exemplo calculator.rb escreva o método class Calculator def sum(n1, n2) seguinte: n1 + n2 end def subtract(n1, n2) n2 - n1 end def multiply(n1, n2) n1 * n2 end def divide(n1, n2) n1 / n2 end end
  • 22. Um pequeno exemplo calculator.rb escreva o método seguinte: rode os testes class Calculator def sum(n1, n2) n1 + n2 $~ ruby test_calculator.rb end Loaded suite test def subtract(n1, n2) Started n2 - n1 EF.E end Finished in 0.0 seconds. def multiply(n1, n2) 1) Failure: n1 * n2 end test_subtract(TestCalculator) [test.rb:35]: def divide(n1, n2) 2 - 1 = 1. n1 / n2 <1> expected but was end end <-1>. ... 4 tests, 1 assertions, 1 failures, 2 errors
  • 23. Um pequeno exemplo calculator.rb escreva o método seguinte: rode os testes class Calculator def sum(n1, n2) n1 + n2 $~ ruby test_calculator.rb end Loaded suite test def subtract(n1, n2) Started n2 - n1 EF.E end Finished in 0.0 seconds. def multiply(n1, n2) 1) Failure: n1 * n2 end test_subtract(TestCalculator) [test.rb:35]: def divide(n1, n2) 2 - 1 = 1. n1 / n2 <1> expected but was end end <-1>. ... 4 tests, 1 assertions, 1 failures, 2 errors 1 falha: nosso código não passou no teste
  • 24. Um pequeno exemplo calculator.rb escreva o método seguinte: rode os testes class Calculator def sum(n1, n2) n1 + n2 $~ ruby test_calculator.rb end Loaded suite test def subtract(n1, n2) Started n2 - n1 EF.E end Finished in 0.0 seconds. def multiply(n1, n2) 1) Failure: n1 * n2 end test_subtract(TestCalculator) [test.rb:35]: def divide(n1, n2) 2 - 1 = 1. n1 / n2 <1> expected but was end end <-1>. ... 4 tests, 1 assertions, 1 failures, 2 errors 1 falha: nosso código não passou no teste devia ser n1 - n2
  • 25. Um pequeno exemplo calculator.rb corrija o método que falhou: class Calculator def sum(n1, n2) n1 + n2 end def subtract(n1, n2) n1 - n2 end def multiply(n1, n2) n1 * n2 end def divide(n1, n2) n1 / n2 end end
  • 26. Um pequeno exemplo calculator.rb corrija o método que falhou: rode os testes class Calculator def sum(n1, n2) n1 + n2 $~ ruby test_calculator.rb end Loaded suite test def subtract(n1, n2) Started n1 - n2 E..E end Finished in 0.0 seconds. def multiply(n1, n2) 1) Error: n1 * n2 end test_divide(TestCalculator): def divide(n1, n2) NoMethodError: undefined method `divide' for #<Calculator: n1 / n2 0x2e2069c> end test.rb:44:in `test_divide‘ end ... 4 tests, 2 assertions, 0 failures, 2 errors
  • 27. Um pequeno exemplo calculator.rb corrija o método que falhou: rode os testes class Calculator def sum(n1, n2) n1 + n2 $~ ruby test_calculator.rb end Loaded suite test def subtract(n1, n2) Started n1 - n2 E..E end Finished in 0.0 seconds. def multiply(n1, n2) 1) Error: n1 * n2 end test_divide(TestCalculator): def divide(n1, n2) NoMethodError: undefined method `divide' for #<Calculator: n1 / n2 0x2e2069c> end test.rb:44:in `test_divide‘ end ... 4 tests, 2 assertions, 0 failures, 2 errors 2 asserções: nosso código passou no teste
  • 28. Um pequeno exemplo calculator.rb continue o processo: class Calculator def sum(n1, n2) n1 + n2 end def subtract(n1, n2) n1 - n2 end def multiply(n1, n2) n1 * n2 end def divide(n1, n2) n1 / n2 end end
  • 29. Um pequeno exemplo calculator.rb continue o processo: execute os testes class Calculator def sum(n1, n2) n1 + n2 $~ ruby test_calculator.rb end ... def subtract(n1, n2) 4 tests, 3 assertions, 0 failures, 1 errors n1 - n2 end def multiply(n1, n2) n1 * n2 end def divide(n1, n2) n1 / n2 end end
  • 30. Um pequeno exemplo calculator.rb continue o processo: execute os testes class Calculator def sum(n1, n2) n1 + n2 $~ ruby test_calculator.rb end ... def subtract(n1, n2) 4 tests, 3 assertions, 0 failures, 1 errors n1 - n2 end def multiply(n1, n2) só mais um: ufa! n1 * n2 end def divide(n1, n2) n1 / n2 end end
  • 31. Um pequeno exemplo calculator.rb escreva o último método: class Calculator def sum(n1, n2) n1 + n2 end def subtract(n1, n2) n1 - n2 end def multiply(n1, n2) n1 * n2 end def divide(n1, n2) n1 / n2 end end
  • 32. Um pequeno exemplo calculator.rb escreva o último método: execute os testes class Calculator def sum(n1, n2) n1 + n2 $~ ruby test_calculator.rb end Loaded suite test def subtract(n1, n2) Started n1 - n2 .... end Finished in 0.0 seconds. def multiply(n1, n2) n1 * n2 end 4 tests, 5 assertions, 0 failures, 0 errors def divide(n1, n2) n1 / n2 end end
  • 33. Um pequeno exemplo calculator.rb escreva o último método: execute os testes class Calculator def sum(n1, n2) n1 + n2 $~ ruby test_calculator.rb end Loaded suite test def subtract(n1, n2) Started n1 - n2 .... end Finished in 0.0 seconds. def multiply(n1, n2) n1 * n2 end 4 tests, 5 assertions, 0 failures, 0 errors def divide(n1, n2) n1 / n2 end 5 asserções, nenhuma falha/erro: código perfeito! end
  • 34. TDD no Rails • Testar uma aplicação no Rails é muito simples • Os testes ficam no diretório test • Os arquivos de testes são criados para você • Apenas um comando: rake test • Dados de testes: fixtures • Testes unitários, funcionais, integração e performance • Mocks & Stubs
  • 35. Fixtures • Conteúdo inicial do modelo • Ficam sob o diretório test/fixtures • SQL, CSV ou YAML Modelo Artist Tabela artists Fixture artists.yml
  • 36. Fixtures test/fixtures/artists.yml nofx: id: 1 name: NOFX url: http://nofxofficialwebsite.com created_at: <%= Time.now.strftime(:db) %> millencolin: id: 2 name: Millencolin url: http://millencolin.com created_at: <%= 3.days.ago.strftime(:db) %>
  • 37. Testes unitários • Testes unitários validam modelos • Ficam sob o diretório test/unit • Arquivo gerado pelo Rails: <model>_test.rb script/generate model Artist test/unit/artist_test.rb
  • 38. Testes unitários test/unit/artist_test.rb require File.dirname(__FILE__) + '/../test_helper' class ArtistTest < Test::Unit::TestCase fixtures :artists # Replace this with your real tests. def test_truth assert true end end
  • 39. Testes unitários test/unit/artist_test.rb require File.dirname(__FILE__) + '/../test_helper' class ArtistTest < Test::Unit::TestCase fixtures :artists def test_should_require_name artist = create(:name => nil) assert_not_nil artist.errors.on(:name), quot;:name should have had an errorquot; assert !artist.valid?, quot;artist should be invalidquot; end private def create(options={}) Artist.create({ :name => 'Death Cab For Cutie', :url => 'http://deathcabforcutie.com' }.merge(options)) end end
  • 40. Testes unitários app/models/artist.rb execute os testes: class Artist < ActiveRecord::Base end
  • 41. Testes unitários app/models/artist.rb execute os testes: rake test:units class Artist < ActiveRecord::Base end $~ rake test:units Loaded suite test Started F Finished in 0.094 seconds. 1) Failure: test_should_require_name(ArtistTest) [./test/ unit/artist_test.rb:8]: :name should have had an error. <nil> expected to not be nil. 1 tests, 1 assertions, 1 failures, 0 errors
  • 42. Testes unitários app/models/artist.rb execute os testes: rake test:units class Artist < ActiveRecord::Base end $~ rake test:units Loaded suite test Started F Finished in 0.094 seconds. 1) Failure: test_should_require_name(ArtistTest) [./test/ unit/artist_test.rb:8]: :name should have had an error. <nil> expected to not be nil. 1 tests, 1 assertions, 1 failures, 0 errors o teste falhou: era esperado!
  • 43. Testes unitários app/models/artist.rb adicione a validação: class Artist < ActiveRecord::Base validates_presence_of :name end
  • 44. Testes unitários app/models/artist.rb adicione a validação: execute os testes class Artist < ActiveRecord::Base validates_presence_of :name $~ rake test:units end Loaded suite test Started . Finished in 0.062 seconds. 1 tests, 2 assertions, 0 failures, 0 errors
  • 45. Testes unitários app/models/artist.rb adicione a validação: execute os testes class Artist < ActiveRecord::Base validates_presence_of :name $~ rake test:units end Loaded suite test Started . Finished in 0.062 seconds. 1 tests, 2 assertions, 0 failures, 0 errors nenhuma falha: voila!
  • 46. Testes funcionais • Testes funcionais validam controles • Ficam sob o diretório test/functional • Template e/ou requisição • Arquivo gerado pelo Rails: <controller>_test.rb script/generate controller artists test/functional/artists_controller_test.rb
  • 47. Testes funcionais test/functional/artists_controller_test.rb require File.dirname(__FILE__) + '/../test_helper‘ require ‘artists_controller‘ # Re-raise errors caught by the controller. class ArtistsController; def rescue_action(e) raise e end; end class ArtistsControllerTest < Test::Unit::TestCase def setup @controller = ArtistsController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end # Replace this with your real tests. def test_truth assert true end end
  • 48. Testes funcionais test/functional/artists_controller_test.rb ... class ArtistsControllerTest < Test::Unit::TestCase def setup @controller = ArtistsController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end def test_index_page get index_path assert_response :success assert_template ‘index’ assert_select ‘h1’, ‘Bands that sound like...’ assert_select ‘form’, {:count => 1, :method} => ‘get’ do assert_select ‘input#name’, :count => 1 assert_select ‘input[type=submit]’, :count => 1 end end end
  • 49. Testes funcionais test/functional/artists_controller_test.rb ... class ArtistsControllerTest < Test::Unit::TestCase def setup @controller = ArtistsController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end def test_index_page get index_path assert_response :success requisição: verificando a resposta assert_template ‘index’ assert_select ‘h1’, ‘Bands that sound like...’ assert_select ‘form’, {:count => 1, :method} => ‘get’ do assert_select ‘input#name’, :count => 1 template: verificando o markup assert_select ‘input[type=submit]’, :count => 1 end end end
  • 50. Testes funcionais execute os testes: ~$ rake test:functionals Loaded suite test Started E Finished in 0.094 seconds. 1) Error: test_index_page(ArtistsControllerTest): ActionController::UnknownAction: No action responded to index ... ./test/functional/artists_controller_test.rb:15:in `test_index_page' 1 tests, 0 assertions, 0 failures, 1 errors
  • 51. Testes funcionais execute os testes: eles devem falhar ~$ rake test:functionals Loaded suite test Started E Finished in 0.094 seconds. 1) Error: test_index_page(ArtistsControllerTest): ActionController::UnknownAction: No action responded to index ... ./test/functional/artists_controller_test.rb:15:in `test_index_page' 1 tests, 0 assertions, 0 failures, 1 errors
  • 52. Testes funcionais execute os testes: eles devem falhar ~$ rake test:functionals Loaded suite test Started E Finished in 0.094 seconds. 1) Error: test_index_page(ArtistsControllerTest): ActionController::UnknownAction: No action responded to index ... ./test/functional/artists_controller_test.rb:15:in `test_index_page' 1 erro: ele já era esperado 1 tests, 0 assertions, 0 failures, 1 errors
  • 53. Testes funcionais execute os testes: eles devem falhar ~$ rake test:functionals Loaded suite test Started E Finished in 0.094 seconds. action: nós ainda não a criamos 1) Error: test_index_page(ArtistsControllerTest): ActionController::UnknownAction: No action responded to index ... ./test/functional/artists_controller_test.rb:15:in `test_index_page' 1 erro: ele já era esperado 1 tests, 0 assertions, 0 failures, 1 errors
  • 54. Testes funcionais crie o template index.rhtml: ~$ rake test:functionals Loaded suite test Started E Finished in 0.094 seconds. 1) Failure: test_index_page(ArtistsControllerTest) [selector_assertions.rb:281:in `assert_select' ./test/functional/artists_controller_test.rb:19:in `test_index_page']: Expected at least 1 elements, found 0. <false> is not true. 1 tests, 3 assertions, 1 failures, 0 errors
  • 55. Testes funcionais crie o template index.rhtml: execute os testes ~$ rake test:functionals Loaded suite test Started E Finished in 0.094 seconds. 1) Failure: test_index_page(ArtistsControllerTest) [selector_assertions.rb:281:in `assert_select' ./test/functional/artists_controller_test.rb:19:in `test_index_page']: Expected at least 1 elements, found 0. <false> is not true. 1 tests, 3 assertions, 1 failures, 0 errors
  • 56. Testes funcionais crie o template index.rhtml: execute os testes ~$ rake test:functionals Loaded suite test Started E Finished in 0.094 seconds. 1) Failure: test_index_page(ArtistsControllerTest) [selector_assertions.rb:281:in `assert_select' ./test/functional/artists_controller_test.rb:19:in `test_index_page']: Expected at least 1 elements, found 0. <false> is not true. 1 erro: ele já era esperado 1 tests, 3 assertions, 1 failures, 0 errors
  • 57. Testes funcionais crie o template index.rhtml: execute os testes ~$ rake test:functionals Loaded suite test Started E Finished in 0.094 seconds. template: nenhum código HTML 1) Failure: test_index_page(ArtistsControllerTest) [selector_assertions.rb:281:in `assert_select' ./test/functional/artists_controller_test.rb:19:in `test_index_page']: Expected at least 1 elements, found 0. <false> is not true. 1 erro: ele já era esperado 1 tests, 3 assertions, 1 failures, 0 errors
  • 58. Testes funcionais app/views/artists/index.rhtml código HTML: <h1>Bands that sound like...</h1> <% form_tag 'view', {:method => :get} do %> <p> <%= text_field_tag :name %> <%= submit_tag ‘View' %> </p> <% end %>
  • 59. Testes funcionais app/views/artists/index.rhtml código HTML: execute os testes <h1>Bands that sound like...</h1> <% form_tag 'view', {:method => :get} do %> ~$ rake test:functionals <p> Loaded suite test <%= text_field_tag :name %> Started <%= submit_tag ‘View' %> . </p> Finished in 0.094 seconds. <% end %> 1 tests, 9 assertions, 0 failures, 0 errors
  • 60. Testes funcionais app/views/artists/index.rhtml código HTML: execute os testes <h1>Bands that sound like...</h1> <% form_tag 'view', {:method => :get} do %> ~$ rake test:functionals <p> Loaded suite test <%= text_field_tag :name %> Started <%= submit_tag ‘View' %> . </p> Finished in 0.094 seconds. <% end %> 1 tests, 9 assertions, 0 failures, 0 errors yep: tudo certo! erros: nenhum para contar história
  • 61. Testes de integração • Testes de integração validam (duh) a integração entre diferentes controllers • Ficam sob o diretório test/integration • Rails não gera arquivo automaticamente: você escolhe! script/generate integration_test artist_stories test/integraton/artist_stories_test.rb
  • 62. Testes de integração test/integration/artist_stories_test.rb require File.dirname(__FILE__) + '/../test_helper' class ArtistStoriesTest < ActionController::IntegrationTest # fixtures :your, :models # Replace this with your real tests. def test_truth assert true end end
  • 63. Testes de integração test/integration/artist_stories_test.rb require File.dirname(__FILE__) + '/../test_helper' class ArtistStoriesTest < ActionController::IntegrationTest fixtures :artists, :albums def test_user_viewing_artist_and_album # user accessing index page get quot;/quot; assert_response :success assert_template quot;indexquot; # searching for an artist get artist_search_path(artists(:millencolin).slug) assert_response :redirect assert_redirected_to quot;/artists/#{artists(:millencolin).slug}quot; # viewing album quot;life on a platequot; get album_path(albums(:life_on_a_plate)) assert_response :success assert_template quot;viewquot; end end
  • 64. Testes de integração test/integration/artist_stories_test.rb require File.dirname(__FILE__) + '/../test_helper' class ArtistStoriesTest < ActionController::IntegrationTest fixtures :artists, :albums def test_user_viewing_artist_and_album # user accessing index page get quot;/quot; controller: / assert_response :success assert_template quot;indexquot; # searching for an artist get artist_search_path(artists(:millencolin).slug) assert_response :redirect controller: /artists/search assert_redirected_to quot;/artists/#{artists(:millencolin).slug}quot; # viewing album quot;life on a platequot; get album_path(albums(:life_on_a_plate)) assert_response :success controller: /albums/ assert_template quot;viewquot; end end
  • 65. Testes de integração • Testes funcionais em um nível mais alto: DSL • Leitura mais fácil, impossível! • Use o método open_session open_session do |session| # Do everything you need! end
  • 66. Testes de integração test/integration/artist_stories_test.rb class ArtistStoriesTest < ActionController::IntegrationTest fixtures :artists, :albums def test_artist_story artist = artists(:millencolin) user = new_session user.search_artist artist user.view_album artist.albums.first end private def new_session open_session do |session| def session.search_artist(artist) get search_artist(artist.name) assert_response :redirect assert_redirected_to artist_path(artist.slug) end def session.view_album(album) get album_path(album.slug) assert_response :success assert_template 'view' end end end end
  • 67. Testes de integração test/integration/artist_stories_test.rb class ArtistStoriesTest < ActionController::IntegrationTest fixtures :artists, :albums def test_artist_story artist = artists(:millencolin) user = new_session user = new_session user.search_artist artist user.search_artist artist user.view_album artist.albums.first end user.view_album artist.albums.first private def new_session open_session do |session| def session.search_artist(artist) get search_artist(artist.name) assert_response :redirect assert_redirected_to artist_path(artist.slug) end def session.view_album(album) get album_path(album.slug) assert_response :success assert_template 'view' end end end end
  • 68. Testes de integração test/integration/artist_stories_test.rb class ArtistStoriesTest < ActionController::IntegrationTest fixtures :artists, :albums def test_artist_story artist = artists(:millencolin) user = new_session user = new_session user.search_artist artist user.search_artist artist user.view_album artist.albums.first end user.view_album artist.albums.first private def new_session open_session do |session| def session.search_artist(artist) get search_artist(artist.name) melhor, impossível! assert_response :redirect assert_redirected_to artist_path(artist.slug) end def session.view_album(album) get album_path(album.slug) assert_response :success assert_template 'view' end end end end
  • 69. Mocks & Stubs • Códigos que eliminam o acesso a um recurso • Ficam sob o diretório test/mocks/test • Deve ter o mesmo nome do arquivo e estrutura da classe/módulo que você quer substituir RAILS_ROOT/lib/launch_missile.rb test/mocks/<RAILS_ENV>/launch_missile.rb
  • 70. Mocks & Stubs lib/feed.rb require ‘open-uri’ class Feed def load(url) open URI.parse(url).read end end
  • 71. Mocks & Stubs lib/feed.rb require ‘open-uri’ class Feed def load(url) open URI.parse(url).read end end não é o ideal: a) pode ser lento; b) pode não estar disponível; c) imagine se fosse transação de pagamento!
  • 72. Mocks & Stubs test/mocks/test/feed.rb require ‘open-uri’ class Feed def load(url) File.new(“#{RAILS_ROOT}/test/fixtures/feed.xml”).read end end
  • 73. Mocks & Stubs test/mocks/test/feed.rb require ‘open-uri’ class Feed def load(url) File.new(“#{RAILS_ROOT}/test/fixtures/feed.xml”).read end end muito mais fácil e rápido: faça quantos pagamentos quiser!