Test-driven Development no Rails
  Começando seu projeto com o pé direito

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


    slides = Array.new
    slides << “O que é TDD?”
    slides << “Por que testar”
    slides << “Um p...
O que é TDD?




   • Test-driven Development ou Desenvolvimento
     Guiado por Testes
   • Uma técnica de desenvolviment...
O que é TDD?



Kent Beck (TDD by Example, 2003):
  1. Escreva um teste que falhe antes de escrever
     qualquer código
 ...
O que é TDD?



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



              ...
Porque testar




“   Isso não me impediu de cometer a tresloucada loucura de
    publicar minha aplicação utilizando Rail...
Porque testar




   Você:
    • escreverá códigos melhores
    • escreverá códigos mais rapidamente
    • identificará er...
Um pequeno exemplo
test_calculator.rb
    class TestCalculator < Test::Unit::TestCase
      def setup
       @calc = Calcu...
Um pequeno exemplo
test_calculator.rb
    class TestCalculator < Test::Unit::TestCase
      def setup
       @calc = Calcu...
Um pequeno exemplo
test_calculator.rb
    class TestCalculator < Test::Unit::TestCase
      def setup
       @calc = Calcu...
Um pequeno exemplo
test_calculator.rb
    class TestCalculator < Test::Unit::TestCase
      def setup
       @calc = Calcu...
Um pequeno exemplo
test_calculator.rb
    class TestCalculator < Test::Unit::TestCase
      def setup
       @calc = Calcu...
Um pequeno exemplo
test_calculator.rb
    class TestCalculator < Test::Unit::TestCase
      def setup
       @calc = Calcu...
Um pequeno exemplo
calculator.rb
    class Calculator
      def sum(n1, n2)
       n1 + n2
      end

     def subtract(n1...
Um pequeno exemplo
calculator.rb

                            execute os testes:
    class Calculator
      def sum(n1, n2...
Um pequeno exemplo
calculator.rb

                            execute os testes: todos eles devem falhar
    class Calcula...
Um pequeno exemplo
calculator.rb

                            execute os testes: todos eles devem falhar
    class Calcula...
Um pequeno exemplo
calculator.rb

                            escreva o primeiro
    class Calculator
      def sum(n1, n2...
Um pequeno exemplo
calculator.rb

                            escreva o primeiro método: rode os testes
    class Calculat...
Um pequeno exemplo
calculator.rb

                            escreva o primeiro método: rode os testes
    class Calculat...
Um pequeno exemplo
calculator.rb

                            escreva o método
    class Calculator
      def sum(n1, n2)
...
Um pequeno exemplo
calculator.rb

                            escreva o método seguinte: rode os testes
    class Calculat...
Um pequeno exemplo
calculator.rb

                            escreva o método seguinte: rode os testes
    class Calculat...
Um pequeno exemplo
calculator.rb

                            escreva o método seguinte: rode os testes
    class Calculat...
Um pequeno exemplo
calculator.rb

                            corrija o método que falhou:
    class Calculator
      def ...
Um pequeno exemplo
calculator.rb

                            corrija o método que falhou: rode os testes
    class Calcul...
Um pequeno exemplo
calculator.rb

                            corrija o método que falhou: rode os testes
    class Calcul...
Um pequeno exemplo
calculator.rb

                            continue o processo:
    class Calculator
      def sum(n1, ...
Um pequeno exemplo
calculator.rb

                            continue o processo: execute os testes
    class Calculator
...
Um pequeno exemplo
calculator.rb

                            continue o processo: execute os testes
    class Calculator
...
Um pequeno exemplo
calculator.rb

                            escreva o último método:
    class Calculator
      def sum(...
Um pequeno exemplo
calculator.rb

                            escreva o último método: execute os testes
    class Calcula...
Um pequeno exemplo
calculator.rb

                            escreva o último método: execute os testes
    class Calcula...
TDD no Rails


  • Testar uma aplicação no Rails é muito simples
  • Os testes ficam no diretório test
  • Os arquivos de ...
Fixtures


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

                  ...
Fixtures
test/fixtures/artists.yml



    nofx:
     id: 1
     name: NOFX
     url: http://nofxofficialwebsite.com
     c...
Testes unitários


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



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

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


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

    class ArtistTest <...
Testes unitários
app/models/artist.rb


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


                                        execute os testes: rake test:units
    cla...
Testes unitários
app/models/artist.rb


                                        execute os testes: rake test:units
    cla...
Testes unitários
app/models/artist.rb


                                        adicione a validação:
    class Artist < A...
Testes unitários
app/models/artist.rb


                                        adicione a validação: execute os testes
  ...
Testes unitários
app/models/artist.rb


                                        adicione a validação: execute os testes
  ...
Testes funcionais


  • Testes funcionais validam controles
  • Ficam sob o diretório test/functional
  • Template e/ou re...
Testes funcionais
test/functional/artists_controller_test.rb


    require File.dirname(__FILE__) + '/../test_helper‘
    ...
Testes funcionais
test/functional/artists_controller_test.rb

...

class ArtistsControllerTest < Test::Unit::TestCase
  de...
Testes funcionais
test/functional/artists_controller_test.rb

...

class ArtistsControllerTest < Test::Unit::TestCase
  de...
Testes funcionais


                                                    execute os testes:
~$ rake test:functionals
Loaded...
Testes funcionais


                                                    execute os testes: eles devem falhar
~$ rake test:...
Testes funcionais


                                                    execute os testes: eles devem falhar
~$ rake test:...
Testes funcionais


                                                    execute os testes: eles devem falhar
~$ rake test:...
Testes funcionais


                                                crie o template index.rhtml:
~$ rake test:functionals
...
Testes funcionais


                                                crie o template index.rhtml: execute os testes
~$ rake...
Testes funcionais


                                                crie o template index.rhtml: execute os testes
~$ rake...
Testes funcionais


                                                crie o template index.rhtml: execute os testes
~$ rake...
Testes funcionais
app/views/artists/index.rhtml


                                               código HTML:
 <h1>Bands t...
Testes funcionais
app/views/artists/index.rhtml


                                               código HTML: execute os t...
Testes funcionais
app/views/artists/index.rhtml


                                               código HTML: execute os t...
Testes de integração


  • Testes de integração validam (duh) a integração entre
    diferentes controllers
  • Ficam sob ...
Testes de integração
test/integration/artist_stories_test.rb



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

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


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

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


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

   ...
Testes de integração


  • Testes funcionais em um nível mais alto: DSL
  • Leitura mais fácil, impossível!
  • Use o méto...
Testes de integração
test/integration/artist_stories_test.rb

 class ArtistStoriesTest < ActionController::IntegrationTest...
Testes de integração
test/integration/artist_stories_test.rb

 class ArtistStoriesTest < ActionController::IntegrationTest...
Testes de integração
test/integration/artist_stories_test.rb

 class ArtistStoriesTest < ActionController::IntegrationTest...
Mocks & Stubs


  • Códigos que eliminam o acesso a um recurso
  • Ficam sob o diretório test/mocks/test
  • Deve ter o me...
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
 ...
Mocks & Stubs
test/mocks/test/feed.rb




 require ‘open-uri’

 class Feed
   def load(url)
    File.new(“#{RAILS_ROOT}/te...
Mocks & Stubs
test/mocks/test/feed.rb




 require ‘open-uri’

 class Feed
   def load(url)
    File.new(“#{RAILS_ROOT}/te...
Dúvidas?
Upcoming SlideShare
Loading in …5
×

Test-driven Development no Rails - Começando com o pé direito

4,355 views
4,307 views

Published on

Published in: Technology

Test-driven Development no Rails - Começando com o pé direito

  1. 1. Test-driven Development no Rails Começando seu projeto com o pé direito 2007, Nando Vieira – http://simplesideias.com.br
  2. 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. 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. 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. 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. 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. 7. Porque testar Você: • escreverá códigos melhores • escreverá códigos mais rapidamente • identificará erros mais facilmente • não usará F5 nunca mais!
  8. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 40. Testes unitários app/models/artist.rb execute os testes: class Artist < ActiveRecord::Base end
  41. 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. 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. 43. Testes unitários app/models/artist.rb adicione a validação: class Artist < ActiveRecord::Base validates_presence_of :name end
  44. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 70. Mocks & Stubs lib/feed.rb require ‘open-uri’ class Feed def load(url) open URI.parse(url).read end end
  71. 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. 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. 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!
  74. 74. Dúvidas?

×