Mini-Curso
TestesOnRails
 Desenvolvimento Orientado a Testes em Rails
                                               1
2
Disclaimer




             3
http://www.railsrx.com   4
O que testar?
    Quando testar?
     Quanto testar?
Quantos asserts por teste?
    Teste quebrado
     mudar teste ou código?

                              5
Contextualização

Testes, Testes Automatizados, Desenvolvimento
     Orientado a Testes, Design Evolutivo,
              Ferramentas de Teste

            TestesOnRails

Unit, Functionals, Integration,View,View Helpers,
          Routes, Performance, Mocks

 Shoulda, RSpec, RSpec-Rails, faker, Cucumber,
                   Koujou
                                                    6
Em
teoria...
            7
Testes
Desenvolver   Testar
Desenvolver   Testar
?
?
$?


?
$
cr
  iaç
          ão

de
     sc
       ob
            er
               ta
co
     rr
       eç
           ão
X
Testes
Automáticos
Programa
Teste



        Programa
Teste



        Programa
Teste



        Programa
(...)
public void meuTeste() {
  int par1 = 1;
  int par2 = 1;
  int result = Classe.soma(par1,par1);
  assertEquals(2, result);
}
(...)




                                (...)
                                public int soma(int a, int b) {
                                  // código
                                }
                                (...)
(...)
public void meuTeste() {
  int par1 = 1;
                                            Preparação
  int par2 = 1;
  int result = Classe.soma(par1,par1);
  assertEquals(2, result);
}
(...)




                                (...)
                                public int soma(int a, int b) {
                                  // código
                                }
                                (...)
(...)
public void meuTeste() {
  int par1 = 1;
  int par2 = 1;
  int result = Classe.soma(par1,par2);
  assertEquals(2, result);
                                              Exercício
}
(...)




                                (...)
                                public int soma(int a, int b) {
                                  // código
                                }
                                (...)
(...)
public void meuTeste() {
  int par1 = 1;
  int par2 = 1;
  int result = Classe.soma(par1,par1);

}
  assertEquals(2, result);
                                             Verificação
(...)




                                (...)
                                public int soma(int a, int b) {
                                  // código
                                }
                                (...)
vale a pena   ?
X
X
X
10




30
10   20




30   30
10   20   30




30   30   30
10   20   30   40




30   30   30   30
10   20   30   40   50




30   30   30   30   30
10   20   30   40   50   60




30   30   30   30   30   30
10   20   30   40   50   60   70




30   30   30   30   30   30   30
public class Romanos {

public static String parse(int entrada) {

        StringBuilder resultado = new StringBuilder();
        if (entrada <= 3) {
          for (int i = 0; i < entrada; i++)
            resultado.append("I");
          return resultado.toString();
        }

        else if (entrada == 4) {
          return "IV";
        } else if(entrada == 5){
          return "V";
        } else if (entrada < 9){
          resultado.append("V");
          return resultado.toString();
        }else if (entrada == 9){
          return "IX";
        }else{
          return "X";
        }
    }


}
public static String parse(int entrada) {

         public static String parse(int entrada) {                  else if (entrada == 4) {
                                                                      return "IV";
                                                                                                              public static String parse(int entrada) {
             else if (entrada == 4) {                               } else if(entrada == 5){
               return "IV";                                           return "V";
                                                                                                                      else if (entrada == 4) {
             } else if(entrada == 5){                               }
                                                                                                                        return "IV";
               return "V";                                                                                            } else if(entrada == 5){
             }                                                  }
                                                                                                                        return "V";
                                                                                                                      }
         }
                                                                                                              }




                                                     public class Romanos {

                                                     public static String parse(int entrada) {

                                                             StringBuilder resultado = new StringBuilder();
public static String parse(int entrada) {                    if (entrada <= 3) {
                                                               for (int i = 0; i < entrada; i++)                  public static String parse(int entrada) {
        else if (entrada == 4) {                                 resultado.append("I");
          return "IV";                                         return resultado.toString();                              else if (entrada == 4) {
        } else if(entrada == 5){                             }                                                             return "IV";
          return "V";                                                                                                    } else if(entrada == 5){
        }                                                    else if (entrada == 4) {                                      return "V";
                                                               return "IV";                                              }
}                                                            } else if(entrada == 5){
                                                               return "V";                                        }
                                                             } else if (entrada < 9){
                                                               resultado.append("V");
                                                               return resultado.toString();
                                                             }else if (entrada == 9){
                                                               return "IX";
                                                             }else{
                                                               return "X";
                                                             }
                                                         }


                                                     }
    public static String parse(int entrada) {                                                                     public static String parse(int entrada) {
         else if (entrada == 4) {                                                                                       else if (entrada == 4) {
           return "IV";                                                                                                   return "IV";
         } else if(entrada == 5){                                                                                       } else if(entrada == 5){
           return "V";                                                                                                    return "V";
         }                                                                                                              }
    }                                                                                                             }
                                                               public static String parse(int entrada) {

                                                                    else if (entrada == 4) {
                                                                      return "IV";
                                                                    } else if(entrada == 5){
                                                                      return "V";
                                                                    }

                                                               }
public static String parse(int entrada) {

         public static String parse(int entrada) {                  else if (entrada == 4) {
                                                                      return "IV";
                                                                                                              public static String parse(int entrada) {
             else if (entrada == 4) {                               } else if(entrada == 5){
               return "IV";                                           return "V";
                                                                                                                      else if (entrada == 4) {
             } else if(entrada == 5){                               }
                                                                                                                        return "IV";
               return "V";                                                                                            } else if(entrada == 5){
             }                                                  }
                                                                                                                        return "V";
                                                                                                                      }
         }
                                                                                                              }




                                                     public class Romanos {

                                                     public static String parse(int entrada) {

                                                             StringBuilder resultado = new StringBuilder();
public static String parse(int entrada) {                    if (entrada <= 3) {
                                                               for (int i = 0; i < entrada; i++)                  public static String parse(int entrada) {
        else if (entrada == 4) {                                 resultado.append("I");
          return "IV";                                         return resultado.toString();                              else if (entrada == 4) {
        } else if(entrada == 5){                             }                                                             return "IV";
          return "V";                                                                                                    } else if(entrada == 5){
        }                                                    else if (entrada == 4) {                                      return "V";
                                                               return "IV";                                              }
}                                                            } else if(entrada == 5){
                                                               return "V";                                        }
                                                             } else if (entrada < 9){
                                                               resultado.append("V");
                                                               return resultado.toString();
                                                             }else if (entrada == 9){
                                                               return "IX";
                                                             }else{
                                                               return "X";
                                                             }
                                                         }


                                                     }
    public static String parse(int entrada) {                                                                     public static String parse(int entrada) {
         else if (entrada == 4) {                                                                                       else if (entrada == 4) {
           return "IV";                                                                                                   return "IV";
         } else if(entrada == 5){                                                                                       } else if(entrada == 5){
           return "V";                                                                                                    return "V";
         }                                                                                                              }
    }                                                                                                             }
                                                               public static String parse(int entrada) {

                                                                    else if (entrada == 4) {
                                                                      return "IV";
                                                                    } else if(entrada == 5){
                                                                      return "V";
                                                                    }

                                                               }
public static String parse(int entrada) {

         public static String parse(int entrada) {                  else if (entrada == 4) {
                                                                      return "IV";
                                                                                                              public static String parse(int entrada) {
             else if (entrada == 4) {                               } else if(entrada == 5){
               return "IV";                                           return "V";
                                                                                                                      else if (entrada == 4) {
             } else if(entrada == 5){                               }
                                                                                                                        return "IV";
               return "V";                                                                                            } else if(entrada == 5){
             }                                                  }
                                                                                                                        return "V";
                                                                                                                      }
         }
                                                                                                              }




                                                     public class Romanos {

                                                     public static String parse(int entrada) {

                                                             StringBuilder resultado = new StringBuilder();
public static String parse(int entrada) {                    if (entrada <= 3) {
                                                               for (int i = 0; i < entrada; i++)                  public static String parse(int entrada) {
        else if (entrada == 4) {                                 resultado.append("I");
          return "IV";                                         return resultado.toString();                              else if (entrada == 4) {
        } else if(entrada == 5){                             }                                                             return "IV";
          return "V";                                                                                                    } else if(entrada == 5){
        }                                                    else if (entrada == 4) {                                      return "V";
                                                               return "IV";                                              }
}                                                            } else if(entrada == 5){
                                                               return "V";                                        }
                                                             } else if (entrada < 9){
                                                               resultado.append("V");
                                                               return resultado.toString();
                                                             }else if (entrada == 9){
                                                               return "IX";
                                                             }else{
                                                               return "X";
                                                             }
                                                         }


                                                     }
    public static String parse(int entrada) {                                                                     public static String parse(int entrada) {
         else if (entrada == 4) {                                                                                       else if (entrada == 4) {
           return "IV";                                                                                                   return "IV";
         } else if(entrada == 5){                                                                                       } else if(entrada == 5){
           return "V";                                                                                                    return "V";
         }                                                                                                              }
    }                                                                                                             }
                                                               public static String parse(int entrada) {

                                                                    else if (entrada == 4) {
                                                                      return "IV";
                                                                    } else if(entrada == 5){
                                                                      return "V";
                                                                    }

                                                               }
evolvability
maintainability

       mantenabilidade
       manutenibilidade
       manutenabilidade

 capacidade de manutenção
Custo




        Tempo
Custo




        Tempo
Test
 Driven
Development
GREEN
RED


        teste


GREEN
RED

código           teste


         GREEN
RED

código           teste


         GREEN

                         refactoring
RED




GREEN
RED
        Plan




GREEN
RED
             Plan


Do
     GREEN
RED
               Plan


Do
     GREEN

       Check
RED
               Plan


Do                    Act
     GREEN

       Check
Design Evolutivo
?
RED




GREEN
Foco

       RED




       GREEN
Foco
Ritmo
        RED




        GREEN
Foco
 Ritmo
             RED
Disciplina




             GREEN
Foco
  Ritmo
               RED
 Disciplina
Simplicidade



               GREEN
Ferramentas
   (Java)
Unidade
Bancos de
 Dados
Aceitação
Aplicações WEB




Selenium
Performance (WEB)
Testes

       Testes Automáticos

Desenvolvimento Orientado a Testes

        Design Evolutivo

          Ferramentas            46
47
http://www.railsrx.com   48
Quando se fala de
testes, fala-se de...
                   Mudanças
Corretude
             Direcionamento
 Robustez
            Design evolutivo
    Documentação               49
O que testar?
       caminho feliz

   caminhos alternativos

erros conhecidos e esperados
                               50
51
TestesOnRails




                52
53
Kiwitter
           54
$ rails kiwitter
    create
    create app/controllers
    create app/helpers
    create app/models
    create app/views/layouts
    create config/environments
    create config/initializers
    create config/locales
    (...)
    create log/server.log
    create log/production.log
    create log/development.log
    create log/test.log
                                 55
kiwitter $ script/generate scaffold user 
                                    login:string 
                                    email:string 
                                    password:string
    exists app/models/
    exists app/controllers/
    exists app/helpers/
    create app/views/users
    exists app/views/layouts/
    (...)
    create test/unit/user_test.rb
    create test/fixtures/users.yml
    create db/migrate
    create db/migrate/20090729120900_create_users.rb
                                                       56
kiwitter $ script/server
=> Booting WEBrick
=> Rails 2.3.3 application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2009-07-29 09:29:22] INFO WEBrick 1.3.1
[2009-07-29 09:29:22] INFO ruby 1.8.7 (2009-06-12) [powerpc-darwin9]
[2009-07-29 09:29:22] INFO WEBrick::HTTPServer#start: pid=54915 port=3000
                                                                       57
kiwitter $ rake db:migrate
(in ...maredeagilidade_ceara/labs/rails_test/kiwitter)
== CreateUsers: migrating ========================================
-- create_table(:users)
   -> 0.0082s
== CreateUsers: migrated (0.0094s) =================================




                                                                       58
Unit
  Functional
 Integration
Performance

Tests
               59
kiwitter $ rake -T
rake test
rake test:benchmark
rake test:functionals
rake test:integration
rake test:plugins
rake test:profile
rake test:recent
rake test:uncommitted
rake test:units         60
kiwitter $ rake test:units

Started
........FE
Finished in 1.181401 seconds.


                                61
........FE
 1) Failure:
test_should_sign_in_only_when_vali
d_credentials_are_given(UserTest) [/
test/unit/user_test.rb:25]:
<nil> is not true.

                                       62
........FE
 2) Error:
test_should_display_user_greetings(
UsersHelperTest):
ArgumentError: wrong number of
arguments (1 for 0)

                                      63
Rails
       environments




test   development   production   64
65
Fixtures



           66
Test fixture refers to the fixed
                    state used as a baseline for
                 running tests in software testing.
                The purpose of a test fixture is to
                ensure that there is a well known
                  and fixed environment in which
                  tests are run so that results are
                repeatable. Some people call this
                          the test context.



http://en.wikipedia.org/wiki/Test_fixture         67
68
http://ar.rubyonrails.org/classes/Fixtures.html   69
Inicialização da base
     database.yml


  Identificação dos
 arquivos de testes
      test/**/*.rb


  Para cada teste
   identificação dos
   métodos de testes
                        70
Para cada método de teste
       test “should xxx yyy”


            1. carrega fixtures
                   test/fixtures/users.yml
            2. executa setup
            3. executa o teste
                           .....FE
            4. executa teardown
            5. “descarrega” fixtures
                     rollback ou delete     71
ios
                 ár
          n   it
       s U
  s t e
Te



                         72
Test::Unit::TestCase
ActiveSupport::TestCase +
Rails Unit Tests

                            73
Rails Unit Tests

 1. fixtures
 2. setup
 3. test/unit/*_test.rb
 4. teardown
                          74
Test::Unit::TestCase
assert
                     assert_not_same
assert_block
                     assert_nothing_raised
assert_equal
                     assert_nothing_thrown
assert_in_delta
                     assert_operator
assert_instance_of
                     assert_raise
assert_kind_of
                     assert_raises
assert_match
                     assert_respond_to
assert_nil
                     assert_same
assert_no_match
                     assert_send
assert_not_equal
                     assert_throws
assert_not_nil
                                             75
http://ruby-doc.org/stdlib/   76
http://api.rubyonrails.org/   77
assert                  assert_nothing_thrown
assert_block            assert_operator
assert_equal            assert_raise
assert_in_delta         assert_raises
assert_instance_of      assert_respond_to
assert_kind_of          assert_same
assert_match            assert_send
assert_nil              assert_throws
assert_no_match         build_message
assert_not_equal        flunk
assert_not_nil          use_pp=
assert_not_same         assert_difference
assert_nothing_raised   assert_no_difference
                                                78
Kiwitter

           79
Kiwitter

           80
81
kiwitter $ rake test:units
...
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/
1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/
unit/helpers/users_helper_test.rb" "test/unit/
user_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/
lib/rake/rake_test_loader
Started
.
Finished in 0.201504 seconds.

1 tests, 1 assertions, 0 failures, 0 errors
                                                         82
83
kiwitter $ rake test:units
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/
lib/rake/rake_test_loader.rb" "test/unit/helpers/users_helper_test.rb" "test/
unit/user_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/
rake_test_loader
Started
.F
Finished in 0.378072 seconds.

 1) Failure:
test_should_require_login(UserTest) [/test/unit/user_test.rb:16]:
<nil> is not true.

2 tests, 2 assertions, 1 failures, 0 errors
rake aborted!
Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...]

(See full trace by running task with --trace)                                     84
85
kiwitter $ rake test:units
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/
gems/1.8/gems/rake-0.8.7/lib/rake/
rake_test_loader.rb" "test/unit/helpers/
users_helper_test.rb" "test/unit/user_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/
rake-0.8.7/lib/rake/rake_test_loader
Started
..
Finished in 0.178493 seconds.

2 tests, 2 assertions, 0 failures, 0 errors
                                                         86
Labs
Desenvolver Orientado a Testes


Validação de obrigatoriedade de senha e email
        Validação de unicidade do login
          Validação formato do email




                                                87
88
89
kiwitter $ rake test:units
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/
rake_test_loader.rb" "test/unit/helpers/users_helper_test.rb" "test/unit/user_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
..E
Finished in 0.322179 seconds.

  1) Error:
test_should_sign_in_only_when_valid_credentials_are_given(UserTest):
NoMethodError: undefined method `signin' for #<Class:0x1a761f0>
   /test/unit/user_test.rb:22:in
`test_should_sign_in_only_when_valid_credentials_are_given'

3 tests, 2 assertions, 0 failures, 1 errors
rake aborted!
Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...]

(See full trace by running task with --trace)
                                                                                      90
1) Error:
test_should_sign_in_only_when_valid_credentials_are_given(UserTest):
ArgumentError: wrong number of arguments (2 for 0)
   /test/unit/user_test.rb:22:in `signin'
   /test/unit/user_test.rb:22:in
`test_should_sign_in_only_when_valid_credentials_are_given'

3 tests, 2 assertions, 0 failures, 1 errors                            91
1) Failure:
test_should_sign_in_only_when_valid_credentials_are_given(UserTest)
[/test/unit/user_test.rb:22]:
<nil> is not true.

3 tests, 3 assertions, 1 failures, 0 errors
                                                                      92
1) Failure:
test_should_sign_in_only_when_valid_credentials_are_given(UserTest)
[/test/unit/user_test.rb:23]:
<false> is not true.

3 tests, 4 assertions, 1 failures, 0 errors
                                                                 93
Quem
espera
 false?
          94
1) Failure:
test_should_sign_in_only_when_valid_credentials_are_given(UserT
est) [/test/unit/user_test.rb:22]:
<nil> is not true.

3 tests, 3 assertions, 1 failures, 0 errors
 1) Failure:
test_should_sign_in_only_when_valid_credentials_are_given(UserT
est) [/test/unit/user_test.rb:23]:
<false> is not true.

3 tests, 4 assertions, 1 failures, 0 errors

      Problema quando se tem vários
       asserts num mesmo test case.                           95
Refactoring




              96
kiwitter $ rake test:units
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/
rake_test_loader.rb" "test/unit/helpers/users_helper_test.rb" "test/unit/user_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
.FF..
Finished in 0.421486 seconds.

 1) Failure:
test_should_not_sign_in_when_invalid_password_is_given(UserTest) [/test/unit/
user_test.rb:27]:
<false> is not true.

 2) Failure:
test_should_not_sign_in_when_invalid_username_is_given(UserTest) [/test/unit/
user_test.rb:31]:
<false> is not true.

5 tests, 5 assertions, 2 failures, 0 errors
rake aborted!
Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...]

(See full trace by running task with --trace)                                              97
1) Failure:
test_should_sign_in_only_when_valid_credentials_are_given(U
serTest) [/test/unit/user_test.rb:23]:
<nil> is not true.

5 tests, 5 assertions, 1 failures, 0 errors
                                                              98
Fixtures
mecanismo para criação de massa de dados de testes




                                                 99
100
101
kiwitter $ rake test:units
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/
gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/unit/
helpers/users_helper_test.rb" "test/unit/user_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/
lib/rake/rake_test_loader
Started
.....
Finished in 0.367962 seconds.

5 tests, 5 assertions, 0 failures, 0 errors

                                                              102
Labs

  Testes unitários como TDD para
criação (post) de mensagens (update)
           por um usuário
                                       103
Testes Funcionais   104
HTTP Req



    ?



           105
Test::Unit::TestCase
ActiveSupport::TestCase    +
ActiveController::TestCase +
Rails Functional Tests

                           106
ActiveController::TestCase
Métodos   Mock Objects     “Hashes”

get       @controller      session
post      @request         cookies
put       @response        flash
delete                     assigns
xhr
          @response.body   session[:user_id]
                                               107
ActiveController::TestCase

assert_dom_equal       assert_select
assert_dom_not_equal   assert_select_email
assert_valid           assert_select_encoded
assert_redirected_to   assert_select_rjs
assert_response        css_select
assert_template        response_from_page_or_rjs
assert_generates       unescape_rjs
assert_recognizes      assert_no_tag
assert_routing         assert_tag

                                              108
1. setup
params = {:project_id => @project.id.to_s, :task_id => @task.id.to_s}
session = {:user_id => 12345}


  2. teste
<método http> <método do controller> <params> <session> <flash>

    get                  :index
   post                 :create               params session
   put                  :update        {:notice => “Task updated”}
  delete                    ...
                                                                   109
Não testa rotas!

*Sempre* enviar parâmetros
    HTTP como string

                             110
st atus
assert_ response

‘c onteúdo’
  assert_t emplate

        ionam ento
redirec       t
     asser t_redirec



                       111
assert_response 200
assert_response 404
assert_response :success
assert_response :missing
assert_template “index”
assert_template “users/new”
assert_redirect_to :controller => task, :id => 3
assert_redirect_to new_task_url
assert_redirect_to @task
                                                   112
Unit Tests


Functional Tests   113
Kiwitter




           114
Kiwitter

       115
kiwitter $ rake test:functionals
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/
rake/rake_test_loader.rb" "test/functional/users_controller_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/
rake_test_loader
Started
F......
Finished in 0.618077 seconds.

 1) Failure:
test_should_create_user(UsersControllerTest) [/test/functional/
users_controller_test.rb:16]:
"User.count" didn't change by 1.
<3> expected but was
<2>.

7 tests, 9 assertions, 1 failures, 0 errors
rake aborted!
Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...]

(See full trace by running task with --trace)                                         116
117
kiwitter $ rake test:functionals
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/
gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/
functional/users_controller_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/
lib/rake/rake_test_loader
Started
.......
Finished in 0.883527 seconds.

7 tests, 10 assertions, 0 failures, 0 errors

                                                              118
119
kiwitter $ script/generate controller sessions new
    exists app/controllers/
    exists app/helpers/
    create app/views/sessions
    exists test/functional/
    exists test/unit/helpers/
    create app/controllers/sessions_controller.rb
    create test/functional/sessions_controller_test.rb
    create app/helpers/sessions_helper.rb
    create test/unit/helpers/sessions_helper_test.rb
    create app/views/sessions/new.html.erb

                                                         120
121
122
kiwitter $ rake test:functionals
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/
rake_test_loader.rb" "test/functional/sessions_controller_test.rb" "test/functional/
users_controller_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
F.......
Finished in 0.842942 seconds.

 1) Failure:
test_should_authenticate_user(SessionsControllerTest) [/test/functional/
sessions_controller_test.rb:8]:
<nil> expected to not be nil.                  assert_not_nil
8 tests, 12 assertions, 1 failures, 0 errors       assigns(:user)
rake aborted!
Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...]

(See full trace by running task with --trace)
                                                                                       123
124
kiwitter $ rake test:functionals
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/
lib/rake/rake_test_loader.rb" "test/functional/sessions_controller_test.rb"
"test/functional/users_controller_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/
rake_test_loader
Started
F.......
Finished in 0.57468 seconds.                      assert_template
                                                 "users/home"
 1) Failure:
test_should_authenticate_user(SessionsControllerTest) [/test/functional/
sessions_controller_test.rb:13]:
expecting <"users/home"> but rendering with <"sessions/create.html.erb">

8 tests, 13 assertions, 1 failures, 0 errors
rake aborted!
Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...]

(See full trace by running task with --trace)                                 125
126
kiwitter $ rake test:functionals
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/
rake/rake_test_loader.rb" "test/functional/sessions_controller_test.rb" "test/
functional/users_controller_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/
rake_test_loader
Started
F.......
                                                       inconsistência
Finished in 0.610806 seconds.

 1) Failure:
test_should_authenticate_user(SessionsControllerTest) [/test/functional/
sessions_controller_test.rb:9]:
Expected response to be a <:success>, but was <302>

8 tests, 11 assertions, 1 failures, 0 errors
rake aborted!
Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...]

(See full trace by running task with --trace)
                                                                                  127
128
kiwitter $ rake test:functionals
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/
rake/rake_test_loader.rb" "test/functional/sessions_controller_test.rb" "test/
functional/users_controller_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/
rake_test_loader
Started                                 redirect não implica na
F.......                              renderização da página de
Finished in 0.99891 seconds.                      destino
 1) Failure:
test_should_authenticate_user(SessionsControllerTest) [/test/functional/
sessions_controller_test.rb:13]:
expecting <"users/home"> but rendering with <"">

8 tests, 13 assertions, 1 failures, 0 errors
rake aborted!
Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...]

(See full trace by running task with --trace)
                                                                                      129
130
kiwitter alegomes$ rake test:functionals
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/
gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/
functional/sessions_controller_test.rb" "test/functional/
users_controller_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/
lib/rake/rake_test_loader
Started
........
Finished in 0.547148 seconds.

8 tests, 12 assertions, 0 failures, 0 errors

                                                             131
Labs
 Testar/implementar autenticação
        de usuário inválido
            @user não deve ser criada
usuário deve ser redirecionado para página de login

          Testar/implementar
          post de mensagem

                                                      132
Testes de Integração




                       133
Req Controller 1


Req Controller 2


Req Controller 3




        ?
                   134
Testes de Integração


Testes de Aceitação
                   135
Integração
desenvolvedores


                X
   linguagem ruby
                    Aceitação
                      clientes
                     linguagem natural




                                         136
TD
não participa do ciclo de




                            137
{post, get, delete...}_via_redirect
             segue todos os redirects

         follow_redirect!
            segue apenas um redirect

                redirect?
        verifica se a última req foi redirect

                   https!
     faz com que todas as reqs pareçam HTTPs

                    host!
             altera o servidor da app
                                               138
139
kiwitter $ script/generate integration_test post_updates
    exists test/integration/
    create test/integration/post_updates_test.rb




                                                       140
141
kiwitter $ rake test:integration
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/
gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/
integration/post_updates_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/
lib/rake/rake_test_loader
Started
.
Finished in 0.255598 seconds.

1 tests, 2 assertions, 0 failures, 0 errors

                                                              142
Lab?   143
Testes da View




                 144
assert_select
                145
Tradeoff



           146
assert_select("form")
       verifica a existência da tag <form>

<span>Maré de Agilidade</span>
    assert_select("span", "Maré de Agilidade")
        assert_select("span", /Agilidade/)



                                                 147
148
149
150
kiwitter $ rake test:integration
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/
gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/
integration/post_updates_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/
lib/rake/rake_test_loader
Started
.
Finished in 0.943481 seconds.

1 tests, 3 assertions, 0 failures, 0 errors

                                                              151
1) Failure:
test_should_post_an_update(PostUpdatesTest) [/test/
integration/post_updates_test.rb:15]:
Expected at least 1 element matching
"div#welcome_messageeeeeeeee", found 0.
<false> is not true.

1 tests, 3 assertions, 1 failures, 0 errors



                                                      152
Testes dos View Helpers




                          153
154
155
156
kiwitter $ rake test:units
/opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/
rake_test_loader.rb" "test/unit/helpers/sessions_helper_test.rb" "test/unit/helpers/
updates_helper_test.rb" "test/unit/helpers/users_helper_test.rb" "test/unit/
update_test.rb" "test/unit/user_test.rb"
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
.......E
Finished in 0.510089 seconds.

 1) Error:
test_should_display_user_greetings(UsersHelperTest):
NoMethodError: undefined method `display_greetings' for #<UsersHelperTest:
0x1ba7e84>
   /test/unit/helpers/users_helper_test.rb:10:in `test_should_display_user_greetings'

8 tests, 8 assertions, 0 failures, 1 errors
rake aborted!
Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...]

(See full trace by running task with --trace)
                                                                                           157
8 tests, 9 assertions, 0 failures, 0 errors
                                              158
Bom
senso

        159
Testes de Rotas




                  160
ActionController::Assertions::RoutingAssertions



assert_generates
assert_generates "/items", :controller => "items", :action => "index"


assert_recognizes
assert_recognizes {:controller => 'items', :action => 'create'},
                  {:path => 'items', :method => :post}


assert_routing
assert_routing '/home', :controller => 'home', :action => 'index'




     http://api.rubyonrails.org/classes/ActionController/Assertions/RoutingAssertions.html   161
Labs
    View
View Helper
   Routes
              162
Mock
Objects

      163
Quem não tem cão...   164
...caça com gato.   165
Objeto real indisponível ou de difícil acesso.

   Reprodução de cenários complexos.




                                                 166
Mocks Aren't Stubs
The term 'Mock Objects' has become a popular one to
describe special case objects that mimic real objects for
testing. Most language environments now have frameworks
that make it easy to create mock objects. What's often not
realized, however, is that mock objects are but one form of
special case test object, one that enables a different style of
testing. In this article I'll explain how mock objects work,
how they encourage testing based on behavior verification,
and how the community around them uses them to develop
a different style of testing.

         http://www.martinfowler.com/articles/mocksArentStubs.html   167
Stu
      168
Objeto falso que retorna um valor predeterminado
          para uma chamada de método

objeto.stubs(:metodo).and_returns("alguma coisa")

 “ignore a implementacao real de objeto.metodo e
              retorne ‘alguma coisa’”

            se objeto.metodo for invocado
                retornará "alguma coisa"

          se objeto.metodo NÃO for invocado
                    nada acontecerá
                                               169
170
17 tests, 28 assertions, 0 failures, 0 errors
                                                171
17 tests, 26 assertions, 1 failures, 0 errors
                                                172
Moc
  173
semelhante ao stub,
            com uma diferença
objeto.stubs(:metodo).adn_returns("alguma coisa")

           se objeto.metodo for invocado
               retornará "alguma coisa"

         se objeto.metodo NÃO for invocado
                    o teste falhará

                                               174
1) Failure:
test_mock_example(UserTest) [/test/unit/user_test.rb:35]:
not all expectations were satisfied
unsatisfied expectations:
- expected exactly once, not yet invoked: #<Mock:0x1884090>.email(any_parameters)
satisfied expectations:
- expected exactly once, already invoked once: #<Mock:0x1884090>.login(any_parameters)

9 tests, 12 assertions, 1 failures, 0 errors
rake aborted!

                                                                                    175
9 tests, 13 assertions, 0 failures, 0 errors




                                               176
mocks      returns
            raises
        any_instance
              with
         pattern matches
                       177
User.any_instance.expects(:login).returns(nil)




  user.login deve ser executado
     apenas uma única vez

                                             178
user.expects(:login).once
user.expects(:login).twice
user.expects(:login).at_least_once
user.expects(:login).at_most_once
user.expects(:login).at_least(3)
user.expects(:login).at_most(3)
user.expects(:login).times(5)
user.expects(:login).times(4..6)
user.expects(:login).never
                                 179
http://flexmock.rubyforge.org
   http://mocha.rubyforge.org
http://double-ruby.rubyforge.org
         http://rspec.info


                                   180
Labs
Stubs e Mocks




                181
http://thoughtbot.com/projects/shoulda   182
context
  setup do
    @u = ....
  end

  should “alguma coisa” do
    assert....
  end
end
                             183
$ sudo gem install thoughtbot-shoulda --source=http://gems.github.com
Password:
Successfully installed thoughtbot-shoulda-2.10.2
1 gem installed
Installing ri documentation for thoughtbot-shoulda-2.10.2...
Installing RDoc documentation for thoughtbot-shoulda-2.10.2...



                http://wiki.github.com/thoughtbot/shoulda/installation   184
require ‘shoulda‘


                185
http://dev.thoughtbot.com/shoulda/   186
assert_accepts
assert_contains
assert_does_not_contain
assert_rejects
assert_same_elements

   http://dev.thoughtbot.com/shoulda/classes/Shoulda/Assertions.html   187
assert_bad_value
assert_good_value
assert_save
assert_valid


http://dev.thoughtbot.com/shoulda/classes/Shoulda/ActiveRecord/Assertions.html   188
assert_did_not_send_email
assert_sent_email



 http://dev.thoughtbot.com/shoulda/classes/Shoulda/ActionMailer/Assertions.html   189
190
should_change                                    should_render_without_layout
should_not_change                                should_respond_with
should_assign_to                                 should_respond_with_content_type
should_filter_params                              should_return_from_session
should_not_assign_to                             should_route
should_not_set_the_flash                          should_set_session
should_redirect_to                               should_set_the_flash_to
should_render_template                           should_render_a_form
should_render_with_layout                        should_render_page_with_metadata




                 http://dev.thoughtbot.com/shoulda/classes/Shoulda/Macros.html
       http://dev.thoughtbot.com/shoulda/classes/Shoulda/ActionController/Macros.html
          http://dev.thoughtbot.com/shoulda/classes/Shoulda/ActionView/Macros.html      191
should_allow_mass_assignment_of
                                                              should_have_named_scope
should_allow_values_for
                                                              should_have_one
should_belong_to
                                                              should_have_readonly_attributes
should_ensure_length_at_least
                                                              should_not_allow_mass_assignment_of
should_ensure_length_in_range
                                                              should_not_allow_values_for
should_ensure_length_is
                                                              should_only_allow_numeric_values_for
should_ensure_value_in_range
                                                              should_protect_attributes
should_have_and_belong_to_many
                                                              should_require_acceptance_of
should_have_class_methods
                                                              should_require_attributes
should_have_db_column
                                                              should_require_unique_attributes
should_have_db_columns
                                                              should_validate_acceptance_of
should_have_index
                                                              should_validate_numericality_of
should_have_indices
                                                              should_validate_presence_of
should_have_instance_methods
                                                              should_validate_uniqueness_of
should_have_many




           http://dev.thoughtbot.com/shoulda/classes/Shoulda/ActiveRecord/Macros.html         192
Lab



  193
194




“    RSpec is
  the original
   Behaviour
           Driven
Development
framework for
       Ruby.

   http://rspec.info
Test Driven *

     corretude            qualidade



< 100%      = 100%



 rebola     a ordem não
no mato       importa
                                      195
testes
           passado
   descrição de algo pronto




     X
especificação
            futuro
  descrição de algo inexistente
                                  196
$ sudo gem install rspec
Password:
**************************************************

 Thank you for installing rspec-1.2.8

 Please be sure to read History.rdoc and Upgrade.rdoc
 for useful information about this release.

**************************************************
Successfully installed rspec-1.2.8
1 gem installed
Installing ri documentation for rspec-1.2.8...
Installing RDoc documentation for rspec-1.2.8...
(...)
                                                        197
kiwitter_rspec $ script/generate rspec
    exists lib/tasks
    create lib/tasks/rspec.rake
    create script/autospec
    create script/spec
    create script/spec_server
    exists spec
    create spec/rcov.opts
    create spec/spec.opts
    create spec/spec_helper.rb
                                     198
kiwitter_rspec $ rake -T
rake spec                   rake spec:plugin_doc
rake spec:clobber_rcov      rake spec:plugins
rake spec:controllers       rake spec:plugins:rspec_on_rails
rake spec:db:fixtures:load   rake spec:rcov
rake spec:doc               rake spec:server:restart
rake spec:helpers           rake spec:server:start
rake spec:integration       rake spec:server:status
rake spec:lib               rake spec:server:stop
rake spec:models            rake spec:views


                                                          199
describe funcionalidade
  it “should do A” do
   ...
   end
   it “should do B” do
      actual.should expected
   end
 ...
end
                               200
201
202
should_not                          should have_at_most
should be_true
                               be_instance_of                      have_exactly
should be_false
                               should_not                          helper
should be_nil
                               be_an_instance_of                   should include
should
                               should be_close                     should_not include
be_[arbitrary_predicate]
                               should_not be_close                 inspect_object
should_not be_nil
                               be_instance_of                      should match
should_not
                               be_kind_of                          should_not match
be_[arbitrary_predicate]
                               should change                       should raise_error
be_a
                               should_not change                   should_not raise_error
should be_kind_of
                               should eql                          should respond_to
should be_a_kind_of
                               should_not eql                      should_not respond_to
should_not be_kind_of
                               should equal                        should satisfy
should_not
                               should_not equal                    should_not satisfy
be_a_kind_of
                               should exist                        simple_matcher
be_an
                               should_not exist                    should throw_symbol
should be_instance_of
                               should have                         should_not
should
                               should_not have                     throw_symbol
be_an_instance_of
                               should have_at_least                wrap_expectation

             http://rspec.rubyforge.org/rspec/1.2.8/classes/Spec/Matchers.html         203
expected.XXXXX?
expected.should be_XXXXX
expected.should be_a_XXXXX
expected.should be_an_XXXXX
expected.should have_key(:k)
expected.has_key?(:k)
expected.should have(10).items
expected.should have(10).laranjas
expected.should have(10).filhos
                                    204
205
206
$ sudo gem install     rspec-rails
Password:
**************************************************

 Thank you for installing rspec-rails-1.2.7.1

 If you are upgrading, do this in each of your rails apps
 that you want to upgrade:

  $ ruby script/generate rspec

 Please be sure to read History.rdoc and Upgrade.rdoc
 for useful information about this release.

**************************************************
Successfully installed rspec-rails-1.2.7.1
1 gem installed
Installing ri documentation for rspec-rails-1.2.7.1...
Installing RDoc documentation for rspec-rails-1.2.7.1...
(...)                                                       207
$ rails kiwitter_rspec
    create
    create app/controllers
    create app/helpers
    create app/models
    create app/views/layouts
    create config/environments
    create config/initializers
    create config/locales
    create db
    create doc
    (...)
                                208
kiwitter_rspec $ script/generate rspec_scaffold user login:string
                                                  password:string
                                                  email:string
    (...)
    create spec/controllers/
    create spec/routing/
    create spec/models/
    create spec/helpers/
    create spec/fixtures/
    create spec/views/users
    create spec/integration/
    (...)
    create spec/views/users/new.html.erb_spec.rb
    create spec/views/users/show.html.erb_spec.rb
    create spec/integration/users_spec.rb
    create db/migrate
    create db/migrate/20090802144903_create_users.rb
     route map.resources :users
                                                                209
script/generate rspec_scaffold update
       user:references message:text



script/generate migration update_user_join


                                             210
Mais testes
gerados que o
  tradicional
 Test::Unit
                211
alta especialização
                      212
Model Spec




             213
Controller Spec




              214
Controller Spec



    response.should
response.should_not
                      {   be_success
                          be_redirect
                          redirect_to(url ou hash)
                          render_template(‘users/home’)




                                                     215
View Spec




            216
View Spec


Test::Unit             RSpec
assigns(@user)        assigns[:user]
 session[:user_id]    session[:user_id]
cookies[“user_id”]   cookies[“user_id”]
   flash[:notice]        flash[:notice]
                                       217
View Spec



                                                    {
                                                                 be_valid
                                                                 have_rjs
                    response.should                              have_tag
                response.should_not                              have_text
                                                                 have_text
                                                                 send_email

response.should have_tag “xxx” do
                                ...
                              end                     {          with_encoded
                                                                 with_tag
                                                                 without_tag

      http://rspec.rubyforge.org/rspec-rails/1.2.7.1/classes/Spec/Rails/Matchers.html   218
Routing Spec




...




                 219
Helper Spec




              220
{
       spec
       spec:controllers
       spec:helpers
       spec:integration
rake   spec:lib
       spec:models
       spec:plugins
       spec:views
                          221
kiwitter_rspec $ rake spec:models
..

Finished in 1.703168 seconds

2 examples, 0 failures

                                222
Lab

      223
faker
 Faker (...) is used to easily
    generate fake data


         http://faker.rubyforge.org   224
kiwitter $ sudo gem install faker
Password:
Successfully installed faker-0.3.1
1 gem installed
Installing ri documentation for faker-0.3.1...
Installing RDoc documentation for faker-0.3.1...


                                               225
require ‘faker‘


                  226
Maida McDermott
April Metz
Rowena Jakubowski
Anita Lueilwitz
Alena Ferry
                    227
puts Faker::Internet.email
mia_schmidt@quigleycrist.ca
nicolette@king.uk
isaac@schmitt.info
cade_buckridge@spinkajaskolski.com
laurine@klein.name


puts Faker::Address.zip_code
11695
72143
21715-9288
15719-7873
90548-7155
                                     228
puts Faker::Lorem.paragraphs(2)
Rerum quos hic et. Autem harum ea asperiores consequatur libero et. Ipsum cumque dicta optio
voluptate. Et quia officia minus iure vitae. Ducimus delectus unde neque odio voluptas
inventore minima.
Fugiat nihil error incidunt nihil quo natus omnis. Quis consequatur aut totam ad. Doloribus
nihil officiis nobis rerum tempora. Nam eos mollitia delectus assumenda veritatis.

Itaque voluptatem repudiandae odit provident error ut. Perspiciatis est facilis sit quis et
qui vel. Hic corrupti recusandae aliquid possimus.
Et error ad ut voluptatem non labore. Accusantium non tempore aut assumenda architecto enim.
Quasi eos et dicta. Tempore quia optio eos pariatur fugiat.

Est neque molestias aliquid et. Dolor cum nemo tempora. Eum ratione esse quam magni officiis
dolor. Earum maxime sit eaque optio laboriosam tempora voluptatibus.
Quo illum ipsa sit. Ea sequi id et sunt nemo quibusdam maxime. Ab voluptate nesciunt maxime
rerum iure explicabo in. Sed quidem dignissimos est officia necessitatibus sed qui. Similique
odit qui id nostrum corporis autem quas enim.

Sunt placeat eum architecto tempora non. Est libero aut repellat mollitia. Quisquam non quia
et id est repellat qui aspernatur.
Animi ut sit quaerat. Dignissimos enim esse autem qui sed aut optio a. Debitis facilis aut
eaque alias exercitationem quia impedit. Maiores vitae id odio est inventore.

Aut accusamus et et vel sint. Quo ducimus dolor nemo quia libero autem. Assumenda est voluptas
debitis in libero.
Illo sit deleniti tenetur nisi. Reiciendis et odit fugiat velit hic. Quo nisi deserunt sit.
                                                                                          229
http://faker.rubyforge.org/rdoc
Array
rand shuffle
Faker::Address
city city_prefix city_suffix secondary_address street_address
street_name street_suffix uk_country uk_county uk_postcode us_state
us_state_abbr zip_code
Faker::Company
bs catch_phrase name suffix
Faker::Internet
domain_name domain_suffix domain_word email free_email user_name
Faker::Lorem
paragraph paragraphs sentence sentences words
Faker::Name
first_name last_name name prefix suffix
Faker::PhoneNumber
phone_number                                                     230
http://cukes.info   231
232
DSL

Rails Test

Rails Code   233
DSL         features
             scenarios




Rails Test     steps




Rails Code               233
$ sudo gem install cucumber
Password:
Successfully installed term-ansicolor-1.0.4
Successfully installed polyglot-0.2.6
Successfully installed treetop-1.3.0
Successfully installed diff-lcs-1.1.2
Successfully installed builder-2.1.2
Successfully installed cucumber-0.3.92
6 gems installed
Installing ri documentation for term-ansicolor-1.0.4...
Installing ri documentation for polyglot-0.2.6...
Installing ri documentation for treetop-1.3.0...
(...)
Installing RDoc documentation for diff-lcs-1.1.2...
Installing RDoc documentation for builder-2.1.2...
Installing RDoc documentation for cucumber-0.3.92...
                                                          234
kiwitter $ script/plugin install git://github.com/brynary/webrat.git
Initialized empty Git repository in .../kiwitter/vendor/plugins/webrat/.git/
remote: Counting objects: 275, done.
remote: Compressing objects: 100% (236/236), done.
remote: Total 275 (delta 36), reused 170 (delta 20)
Receiving objects: 100% (275/275), 5.07 MiB | 154 KiB/s, done.
Resolving deltas: 100% (36/36), done.
From git://github.com/brynary/webrat
 * branch         HEAD        -> FETCH_HEAD
= Webrat - Ruby Acceptance Testing for Web applications
...
== Description

Webrat lets you quickly write expressive and robust acceptance tests for a Ruby
web application.



                                                                            235
kiwitter $ sudo gem install nokogiri
Building native extensions. This could take a while...
Successfully installed nokogiri-1.3.3
1 gem installed
Installing ri documentation for nokogiri-1.3.3...
Installing RDoc documentation for nokogiri-1.3.3...



                                                         236
kiwitter $ script/generate cucumber
    create features/step_definitions
    create features/step_definitions/webrat_steps.rb
    create config/environments/cucumber.rb
    create features/support
    create features/support/env.rb
    create features/support/paths.rb
    exists lib/tasks
    create lib/tasks/cucumber.rake
    create script/cucumber

                                                      237
Feature: caso de uso/estória em teste
 In order objetivo da funcionalidade
 Stakeholder
 o que o stakeholder deseja

 Background
  Given pré-condições
  And mais pré-condições
    | login    | email              | password |
    | alegomes | alegomes@gmail.com | ale123   |
    | luciana | lu@brasilia.net     | xuxu     |


  Scenario: cenário/fluxo em teste
    Given pré-condições
    When ação do usuário
    Then resultado da ação do usuário              238
kiwitter $ script/generate feature users_and_updates
   exists features/step_definitions
   create features/manage_users_and_updates.feature
   create features/step_definitions/users_and_updates_steps.rb




                                                           239
DSL

Rails Test

Rails Code   240
Teste de
 aceitação
gerado pelo
 Cucumber



              241
modificado para o kiwitter   242
kiwitter $ rake features
/opt/local/bin/ruby -I "/opt/local/lib/ruby/gems/1.8/gems/cucumber-0.3.92/lib:lib" "/opt/local/lib/
ruby/gems/1.8/gems/cucumber-0.3.92/bin/cucumber" --format pretty features/
manage_users_and_updates.feature
Feature: Post update messages
  In order to make my life widely public
  As a User
  I want to post short messages describing what I am doing

  Scenario: Post new messages                         # features/manage_users_and_updates.feature:6
    Given I am at users home page                     # features/manage_users_and_updates.feature:7
    And I have entered a text message up to 140 chars # features/manage_users_and_updates.feature:8
    When I press post                                 # features/manage_users_and_updates.feature:9
    Then the message should be registered             # features/manage_users_and_updates.feature:10

1 scenario (1 undefined)
4 steps (4 undefined)
0m0.653s

...




                                                                                                243
...

You can implement step definitions for undefined steps with these
snippets:

Given /^I am at users home page$/ do
  pending
end

Given /^I have entered a text message up to 140 chars$/ do
  pending
end

When /^I press post$/ do
  pending
end

Then /^the message should be registered$/ do
  pending
end


                                                               244
DSL

Rails Test

Rails Code   245
Feature steps
gerados pelo

script/generate
    feature


                246
...

You can implement step definitions for undefined steps with
these snippets:

Given /^I am at users home page$/ do
  pending
end

Given /^I have entered a text message up to 140 chars$/ do
  pending
end

When /^I press post$/ do
  pending
end

Then /^the message should be registered$/ do
  pending
end
                                                              247
kiwitter $ rake features
/opt/local/bin/ruby -I "/opt/local/lib/ruby/gems/1.8/gems/cucumber-0.3.92/lib:lib" "/opt/
local/lib/ruby/gems/1.8/gems/cucumber-0.3.92/bin/cucumber" --format pretty features/
manage_users_and_updates.feature
Feature: Post update messages
  In order to make my life widely public
 As a User
  I want to post short messages describing what I am doing

 Scenario: Post new messages
  Given I am at users home page
   TODO (Cucumber::Pending)
   features/manage_users_and_updates.feature:7:in `Given I am at users home page'
  And I have entered a text message up to 140 chars
  When I press post
  Then the message should be registered

1 scenario (1 pending)
4 steps (3 skipped, 1 pending)
0m0.134s
                                                                                       248
Given I am at users home page
   TODO (Cucumber::Pending)
    features/manage_users_and_updates.feature:7:in `Given I am at users home page'




  Given /^I am at users home page$/ do
    visit "users/home"
  end




                                                                                     249
kiwitter $ rake features
...
Scenario: Post new messages
users_controller.home
    Given I am at users home page
    And I have entered a text message up to 140 chars
     TODO (Cucumber::Pending)
     features/manage_users_and_updates.feature:8:in `And I
have entered a text message up to 140 chars'
    When I press post
    Then the message should be registered

1 scenario (1 pending)
4 steps (2 skipped, 1 pending, 1 passed)
0m0.260s                                                 250
And I have entered a text message up to 140 chars
    TODO (Cucumber::Pending)
    features/manage_users_and_updates.feature:8:in `And I have entered a
text message up to 140 chars'




                                                                           251
kiwitter $ cucumber features/manage_users_and_updates.feature
Feature: Post update messages
 In order to make my life widely public
 As a User
 I want to post short messages describing what I am doing

 Scenario: Post new messages
users_controller.home
  Given I am at users home page
   And I have entered a text message up to 140 chars
  When I press post
   TODO (Cucumber::Pending)
    features/manage_users_and_updates.feature:9:in `When I press post'
  Then the message should be registered

1 scenario (1 pending)
4 steps (1 skipped, 1 pending, 2 passed)
0m0.305s
                                                                         252
When I press post
  TODO (Cucumber::Pending)
  features/manage_users_and_updates.feature:9:in `When I press post'




                                                                       253
kiwitter $ cucumber features/manage_users_and_updates.feature
Feature: Post update messages
 In order to make my life widely public
 As a User
 I want to post short messages describing what I am doing

 Scenario: Post new messages
users_controller.home
  Given I am at users home page
  And I have entered a text message up to 140 chars
  When I press post
  Then the message should be registered
   TODO (Cucumber::Pending)
    features/manage_users_and_updates.feature:10:in `Then the
message should be registered'

1 scenario (1 pending)
4 steps (1 pending, 3 passed)
0m0.282s                                                        254
Then the message should be registered
   TODO (Cucumber::Pending)
   features/manage_users_and_updates.feature:10:in `Then the message should be registered'




                                         ?
                                                                                             255
webrat




    http://github.com/brynary/webrat/tree/master   256
kiwitter $ script/plugin install git://github.com/brynary/webrat.git
Initialized empty Git repository in .../kiwitter/vendor/plugins/webrat/.git/
remote: Counting objects: 275, done.
remote: Compressing objects: 100% (236/236), done.
remote: Total 275 (delta 36), reused 170 (delta 20)
Receiving objects: 100% (275/275), 5.07 MiB | 125 KiB/s, done.
Resolving deltas: 100% (36/36), done.
From git://github.com/brynary/webrat
 * branch         HEAD        -> FETCH_HEAD
(= Webrat - Ruby Acceptance Testing for Web applications

- http://gitrdoc.com/brynary/webrat
- http://groups.google.com/group/webrat
- http://webrat.lighthouseapp.com/
- http://github.com/brynary/webrat
- #webrat on Freenode
(...)

                                                                          257
http://www.zenspider.com/ZSS/Products/ZenTest/   258
http://www.michaelleung.us/koujou   259
http://eigenclass.org/hiki/rcov   260
$ sudo gem install rcov
Password:
Building native extensions. This could take a while...
Successfully installed rcov-0.8.1.2.0
1 gem installed
Installing ri documentation for rcov-0.8.1.2.0...
Installing RDoc documentation for rcov-0.8.1.2.0...



                                                         261
$ rcov --version
rcov 0.8.1.2 2007-11-22


                          262
kiwitter $ ./script/plugin install --force http://svn.codahale.com/rails_rcov
+ ./MIT-LICENSE
+ ./README
+ ./tasks/rails_rcov.rake




                    http://agilewebdevelopment.com/plugins/rails_rcov      263
kiwitter $ rake -T | grep rcov
rake doc:plugins:rails_rcov
                                     rake test:profile:clobber_rcov
rake spec:clobber_rcov
                                     rake test:profile:rcov
rake spec:rcov
                                     rake test:recent:clobber_rcov
rake test:benchmark:clobber_rcov
                                     rake test:recent:rcov
rake test:benchmark:rcov
                                     rake test:test:clobber_rcov
rake test:functionals:clobber_rcov
                                     rake test:test:rcov
rake test:functionals:rcov
                                     rake test:uncommitted:clobber_rcov
rake test:integration:clobber_rcov
                                     rake test:uncommitted:rcov
rake test:integration:rcov
                                     rake test:units:clobber_rcov
rake test:plugins:clobber_rcov
                                     rake test:units:rcov
rake test:plugins:rcov



                                                                     264
kiwitter $ rake test:units:rcov
                 10 tests, 13 assertions, 1 failures, 1 errors
+----------------------------------------------------+-------+-------+--------+
|                   File                             | Lines | LOC | COV       |
+----------------------------------------------------+-------+-------+--------+
|.../ruby/1.8/gems/sqlite3-ruby-1.2.5/lib/sqlite3.rb |     1 |     1 | 100.0% |
|...gems/sqlite3-ruby-1.2.5/lib/sqlite3/constants.rb |    49 |    44 | 97.7% |
|.../gems/sqlite3-ruby-1.2.5/lib/sqlite3/database.rb |   721 |   340 | 40.3% |
|...3-ruby-1.2.5/lib/sqlite3/driver/native/driver.rb |   219 |   180 | 48.3% |
|....8/gems/sqlite3-ruby-1.2.5/lib/sqlite3/errors.rb |    68 |    58 | 84.5% |
|...8/gems/sqlite3-ruby-1.2.5/lib/sqlite3/pragmas.rb |   271 |   190 | 45.8% |
|...gems/sqlite3-ruby-1.2.5/lib/sqlite3/resultset.rb |   180 |   114 | 72.8% |
|...gems/sqlite3-ruby-1.2.5/lib/sqlite3/statement.rb |   231 |   128 | 50.0% |
|...ems/sqlite3-ruby-1.2.5/lib/sqlite3/translator.rb |   109 |    64 | 20.3% |
|...1.8/gems/sqlite3-ruby-1.2.5/lib/sqlite3/value.rb |    57 |    44 | 29.5% |
|app/controllers/application_controller.rb           |    48 |    21 | 23.8% |
|app/controllers/sessions_controller.rb              |    32 |     9 | 22.2% |
|app/controllers/updates_controller.rb               |    85 |    60 | 13.3% |
|app/controllers/users_controller.rb                 |    89 |    63 | 14.3% |
|app/helpers/application_helper.rb                   |     3 |     2 | 100.0% |
|app/helpers/sessions_helper.rb                      |     3 |     2 | 100.0% |
|app/helpers/updates_helper.rb                       |     2 |     2 | 100.0% |
|app/helpers/users_helper.rb                         |     8 |     5 | 40.0% |
|app/models/update.rb                                |     5 |     4 | 100.0% |
|app/models/user.rb                                  |     8 |     6 | 100.0% |
+----------------------------------------------------+-------+-------+--------+
|Total                                               | 2189 | 1337 | 46.3% |
                                                                              265
+----------------------------------------------------+-------+-------+--------+
266
Q&A

Minicurso de TestesOnRails

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
    O que testar? Quando testar? Quanto testar? Quantos asserts por teste? Teste quebrado mudar teste ou código? 5
  • 6.
    Contextualização Testes, Testes Automatizados,Desenvolvimento Orientado a Testes, Design Evolutivo, Ferramentas de Teste TestesOnRails Unit, Functionals, Integration,View,View Helpers, Routes, Performance, Mocks Shoulda, RSpec, RSpec-Rails, faker, Cucumber, Koujou 6
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
    $ cr iaç ão de sc ob er ta co rr eç ão
  • 15.
  • 17.
  • 18.
  • 19.
    Teste Programa
  • 20.
    Teste Programa
  • 21.
    Teste Programa
  • 22.
    (...) public void meuTeste(){ int par1 = 1; int par2 = 1; int result = Classe.soma(par1,par1); assertEquals(2, result); } (...) (...) public int soma(int a, int b) { // código } (...)
  • 23.
    (...) public void meuTeste(){ int par1 = 1; Preparação int par2 = 1; int result = Classe.soma(par1,par1); assertEquals(2, result); } (...) (...) public int soma(int a, int b) { // código } (...)
  • 24.
    (...) public void meuTeste(){ int par1 = 1; int par2 = 1; int result = Classe.soma(par1,par2); assertEquals(2, result); Exercício } (...) (...) public int soma(int a, int b) { // código } (...)
  • 25.
    (...) public void meuTeste(){ int par1 = 1; int par2 = 1; int result = Classe.soma(par1,par1); } assertEquals(2, result); Verificação (...) (...) public int soma(int a, int b) { // código } (...)
  • 26.
  • 27.
  • 28.
  • 29.
  • 31.
  • 32.
    10 20 30 30
  • 33.
    10 20 30 30 30 30
  • 34.
    10 20 30 40 30 30 30 30
  • 35.
    10 20 30 40 50 30 30 30 30 30
  • 36.
    10 20 30 40 50 60 30 30 30 30 30 30
  • 37.
    10 20 30 40 50 60 70 30 30 30 30 30 30 30
  • 39.
    public class Romanos{ public static String parse(int entrada) { StringBuilder resultado = new StringBuilder(); if (entrada <= 3) { for (int i = 0; i < entrada; i++) resultado.append("I"); return resultado.toString(); } else if (entrada == 4) { return "IV"; } else if(entrada == 5){ return "V"; } else if (entrada < 9){ resultado.append("V"); return resultado.toString(); }else if (entrada == 9){ return "IX"; }else{ return "X"; } } }
  • 40.
    public static Stringparse(int entrada) { public static String parse(int entrada) { else if (entrada == 4) { return "IV"; public static String parse(int entrada) { else if (entrada == 4) { } else if(entrada == 5){ return "IV"; return "V"; else if (entrada == 4) { } else if(entrada == 5){ } return "IV"; return "V"; } else if(entrada == 5){ } } return "V"; } } } public class Romanos { public static String parse(int entrada) { StringBuilder resultado = new StringBuilder(); public static String parse(int entrada) { if (entrada <= 3) { for (int i = 0; i < entrada; i++) public static String parse(int entrada) { else if (entrada == 4) { resultado.append("I"); return "IV"; return resultado.toString(); else if (entrada == 4) { } else if(entrada == 5){ } return "IV"; return "V"; } else if(entrada == 5){ } else if (entrada == 4) { return "V"; return "IV"; } } } else if(entrada == 5){ return "V"; } } else if (entrada < 9){ resultado.append("V"); return resultado.toString(); }else if (entrada == 9){ return "IX"; }else{ return "X"; } } } public static String parse(int entrada) { public static String parse(int entrada) { else if (entrada == 4) { else if (entrada == 4) { return "IV"; return "IV"; } else if(entrada == 5){ } else if(entrada == 5){ return "V"; return "V"; } } } } public static String parse(int entrada) { else if (entrada == 4) { return "IV"; } else if(entrada == 5){ return "V"; } }
  • 41.
    public static Stringparse(int entrada) { public static String parse(int entrada) { else if (entrada == 4) { return "IV"; public static String parse(int entrada) { else if (entrada == 4) { } else if(entrada == 5){ return "IV"; return "V"; else if (entrada == 4) { } else if(entrada == 5){ } return "IV"; return "V"; } else if(entrada == 5){ } } return "V"; } } } public class Romanos { public static String parse(int entrada) { StringBuilder resultado = new StringBuilder(); public static String parse(int entrada) { if (entrada <= 3) { for (int i = 0; i < entrada; i++) public static String parse(int entrada) { else if (entrada == 4) { resultado.append("I"); return "IV"; return resultado.toString(); else if (entrada == 4) { } else if(entrada == 5){ } return "IV"; return "V"; } else if(entrada == 5){ } else if (entrada == 4) { return "V"; return "IV"; } } } else if(entrada == 5){ return "V"; } } else if (entrada < 9){ resultado.append("V"); return resultado.toString(); }else if (entrada == 9){ return "IX"; }else{ return "X"; } } } public static String parse(int entrada) { public static String parse(int entrada) { else if (entrada == 4) { else if (entrada == 4) { return "IV"; return "IV"; } else if(entrada == 5){ } else if(entrada == 5){ return "V"; return "V"; } } } } public static String parse(int entrada) { else if (entrada == 4) { return "IV"; } else if(entrada == 5){ return "V"; } }
  • 42.
    public static Stringparse(int entrada) { public static String parse(int entrada) { else if (entrada == 4) { return "IV"; public static String parse(int entrada) { else if (entrada == 4) { } else if(entrada == 5){ return "IV"; return "V"; else if (entrada == 4) { } else if(entrada == 5){ } return "IV"; return "V"; } else if(entrada == 5){ } } return "V"; } } } public class Romanos { public static String parse(int entrada) { StringBuilder resultado = new StringBuilder(); public static String parse(int entrada) { if (entrada <= 3) { for (int i = 0; i < entrada; i++) public static String parse(int entrada) { else if (entrada == 4) { resultado.append("I"); return "IV"; return resultado.toString(); else if (entrada == 4) { } else if(entrada == 5){ } return "IV"; return "V"; } else if(entrada == 5){ } else if (entrada == 4) { return "V"; return "IV"; } } } else if(entrada == 5){ return "V"; } } else if (entrada < 9){ resultado.append("V"); return resultado.toString(); }else if (entrada == 9){ return "IX"; }else{ return "X"; } } } public static String parse(int entrada) { public static String parse(int entrada) { else if (entrada == 4) { else if (entrada == 4) { return "IV"; return "IV"; } else if(entrada == 5){ } else if(entrada == 5){ return "V"; return "V"; } } } } public static String parse(int entrada) { else if (entrada == 4) { return "IV"; } else if(entrada == 5){ return "V"; } }
  • 43.
    evolvability maintainability mantenabilidade manutenibilidade manutenabilidade capacidade de manutenção
  • 44.
    Custo Tempo
  • 45.
    Custo Tempo
  • 46.
  • 47.
  • 48.
    RED teste GREEN
  • 49.
    RED código teste GREEN
  • 50.
    RED código teste GREEN refactoring
  • 51.
  • 52.
    RED Plan GREEN
  • 53.
    RED Plan Do GREEN
  • 54.
    RED Plan Do GREEN Check
  • 55.
    RED Plan Do Act GREEN Check
  • 56.
  • 66.
  • 72.
  • 73.
    Foco RED GREEN
  • 74.
    Foco Ritmo RED GREEN
  • 75.
    Foco Ritmo RED Disciplina GREEN
  • 76.
    Foco Ritmo RED Disciplina Simplicidade GREEN
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
    Testes Testes Automáticos Desenvolvimento Orientado a Testes Design Evolutivo Ferramentas 46
  • 84.
  • 85.
  • 86.
    Quando se falade testes, fala-se de... Mudanças Corretude Direcionamento Robustez Design evolutivo Documentação 49
  • 87.
    O que testar? caminho feliz caminhos alternativos erros conhecidos e esperados 50
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
    $ rails kiwitter create create app/controllers create app/helpers create app/models create app/views/layouts create config/environments create config/initializers create config/locales (...) create log/server.log create log/production.log create log/development.log create log/test.log 55
  • 93.
    kiwitter $ script/generatescaffold user login:string email:string password:string exists app/models/ exists app/controllers/ exists app/helpers/ create app/views/users exists app/views/layouts/ (...) create test/unit/user_test.rb create test/fixtures/users.yml create db/migrate create db/migrate/20090729120900_create_users.rb 56
  • 94.
    kiwitter $ script/server =>Booting WEBrick => Rails 2.3.3 application starting on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server [2009-07-29 09:29:22] INFO WEBrick 1.3.1 [2009-07-29 09:29:22] INFO ruby 1.8.7 (2009-06-12) [powerpc-darwin9] [2009-07-29 09:29:22] INFO WEBrick::HTTPServer#start: pid=54915 port=3000 57
  • 95.
    kiwitter $ rakedb:migrate (in ...maredeagilidade_ceara/labs/rails_test/kiwitter) == CreateUsers: migrating ======================================== -- create_table(:users) -> 0.0082s == CreateUsers: migrated (0.0094s) ================================= 58
  • 96.
    Unit Functional Integration Performance Tests 59
  • 97.
    kiwitter $ rake-T rake test rake test:benchmark rake test:functionals rake test:integration rake test:plugins rake test:profile rake test:recent rake test:uncommitted rake test:units 60
  • 98.
    kiwitter $ raketest:units Started ........FE Finished in 1.181401 seconds. 61
  • 99.
  • 100.
  • 101.
    Rails environments test development production 64
  • 102.
  • 103.
  • 104.
    Test fixture refersto the fixed state used as a baseline for running tests in software testing. The purpose of a test fixture is to ensure that there is a well known and fixed environment in which tests are run so that results are repeatable. Some people call this the test context. http://en.wikipedia.org/wiki/Test_fixture 67
  • 105.
  • 106.
  • 107.
    Inicialização da base database.yml Identificação dos arquivos de testes test/**/*.rb Para cada teste identificação dos métodos de testes 70
  • 108.
    Para cada métodode teste test “should xxx yyy” 1. carrega fixtures test/fixtures/users.yml 2. executa setup 3. executa o teste .....FE 4. executa teardown 5. “descarrega” fixtures rollback ou delete 71
  • 109.
    ios ár n it s U s t e Te 72
  • 110.
  • 111.
    Rails Unit Tests 1. fixtures 2. setup 3. test/unit/*_test.rb 4. teardown 74
  • 112.
    Test::Unit::TestCase assert assert_not_same assert_block assert_nothing_raised assert_equal assert_nothing_thrown assert_in_delta assert_operator assert_instance_of assert_raise assert_kind_of assert_raises assert_match assert_respond_to assert_nil assert_same assert_no_match assert_send assert_not_equal assert_throws assert_not_nil 75
  • 113.
  • 114.
  • 115.
    assert assert_nothing_thrown assert_block assert_operator assert_equal assert_raise assert_in_delta assert_raises assert_instance_of assert_respond_to assert_kind_of assert_same assert_match assert_send assert_nil assert_throws assert_no_match build_message assert_not_equal flunk assert_not_nil use_pp= assert_not_same assert_difference assert_nothing_raised assert_no_difference 78
  • 116.
  • 117.
  • 118.
  • 119.
    kiwitter $ raketest:units ... /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/ 1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/ unit/helpers/users_helper_test.rb" "test/unit/ user_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/ lib/rake/rake_test_loader Started . Finished in 0.201504 seconds. 1 tests, 1 assertions, 0 failures, 0 errors 82
  • 120.
  • 121.
    kiwitter $ raketest:units /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/ lib/rake/rake_test_loader.rb" "test/unit/helpers/users_helper_test.rb" "test/ unit/user_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/ rake_test_loader Started .F Finished in 0.378072 seconds. 1) Failure: test_should_require_login(UserTest) [/test/unit/user_test.rb:16]: <nil> is not true. 2 tests, 2 assertions, 1 failures, 0 errors rake aborted! Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...] (See full trace by running task with --trace) 84
  • 122.
  • 123.
    kiwitter $ raketest:units /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/ gems/1.8/gems/rake-0.8.7/lib/rake/ rake_test_loader.rb" "test/unit/helpers/ users_helper_test.rb" "test/unit/user_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/ rake-0.8.7/lib/rake/rake_test_loader Started .. Finished in 0.178493 seconds. 2 tests, 2 assertions, 0 failures, 0 errors 86
  • 124.
    Labs Desenvolver Orientado aTestes Validação de obrigatoriedade de senha e email Validação de unicidade do login Validação formato do email 87
  • 125.
  • 126.
  • 127.
    kiwitter $ raketest:units /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/ rake_test_loader.rb" "test/unit/helpers/users_helper_test.rb" "test/unit/user_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader Started ..E Finished in 0.322179 seconds. 1) Error: test_should_sign_in_only_when_valid_credentials_are_given(UserTest): NoMethodError: undefined method `signin' for #<Class:0x1a761f0> /test/unit/user_test.rb:22:in `test_should_sign_in_only_when_valid_credentials_are_given' 3 tests, 2 assertions, 0 failures, 1 errors rake aborted! Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...] (See full trace by running task with --trace) 90
  • 128.
    1) Error: test_should_sign_in_only_when_valid_credentials_are_given(UserTest): ArgumentError: wrongnumber of arguments (2 for 0) /test/unit/user_test.rb:22:in `signin' /test/unit/user_test.rb:22:in `test_should_sign_in_only_when_valid_credentials_are_given' 3 tests, 2 assertions, 0 failures, 1 errors 91
  • 129.
  • 130.
  • 131.
  • 132.
    1) Failure: test_should_sign_in_only_when_valid_credentials_are_given(UserT est) [/test/unit/user_test.rb:22]: <nil>is not true. 3 tests, 3 assertions, 1 failures, 0 errors 1) Failure: test_should_sign_in_only_when_valid_credentials_are_given(UserT est) [/test/unit/user_test.rb:23]: <false> is not true. 3 tests, 4 assertions, 1 failures, 0 errors Problema quando se tem vários asserts num mesmo test case. 95
  • 133.
  • 134.
    kiwitter $ raketest:units /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/ rake_test_loader.rb" "test/unit/helpers/users_helper_test.rb" "test/unit/user_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader Started .FF.. Finished in 0.421486 seconds. 1) Failure: test_should_not_sign_in_when_invalid_password_is_given(UserTest) [/test/unit/ user_test.rb:27]: <false> is not true. 2) Failure: test_should_not_sign_in_when_invalid_username_is_given(UserTest) [/test/unit/ user_test.rb:31]: <false> is not true. 5 tests, 5 assertions, 2 failures, 0 errors rake aborted! Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...] (See full trace by running task with --trace) 97
  • 135.
  • 136.
    Fixtures mecanismo para criaçãode massa de dados de testes 99
  • 137.
  • 138.
  • 139.
    kiwitter $ raketest:units /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/ gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/unit/ helpers/users_helper_test.rb" "test/unit/user_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/ lib/rake/rake_test_loader Started ..... Finished in 0.367962 seconds. 5 tests, 5 assertions, 0 failures, 0 errors 102
  • 140.
    Labs Testesunitários como TDD para criação (post) de mensagens (update) por um usuário 103
  • 141.
  • 142.
    HTTP Req ? 105
  • 143.
    Test::Unit::TestCase ActiveSupport::TestCase + ActiveController::TestCase + Rails Functional Tests 106
  • 144.
    ActiveController::TestCase Métodos Mock Objects “Hashes” get @controller session post @request cookies put @response flash delete assigns xhr @response.body session[:user_id] 107
  • 145.
    ActiveController::TestCase assert_dom_equal assert_select assert_dom_not_equal assert_select_email assert_valid assert_select_encoded assert_redirected_to assert_select_rjs assert_response css_select assert_template response_from_page_or_rjs assert_generates unescape_rjs assert_recognizes assert_no_tag assert_routing assert_tag 108
  • 146.
    1. setup params ={:project_id => @project.id.to_s, :task_id => @task.id.to_s} session = {:user_id => 12345} 2. teste <método http> <método do controller> <params> <session> <flash> get :index post :create params session put :update {:notice => “Task updated”} delete ... 109
  • 147.
    Não testa rotas! *Sempre*enviar parâmetros HTTP como string 110
  • 148.
    st atus assert_ response ‘conteúdo’ assert_t emplate ionam ento redirec t asser t_redirec 111
  • 149.
    assert_response 200 assert_response 404 assert_response:success assert_response :missing assert_template “index” assert_template “users/new” assert_redirect_to :controller => task, :id => 3 assert_redirect_to new_task_url assert_redirect_to @task 112
  • 150.
  • 151.
  • 152.
  • 153.
    kiwitter $ raketest:functionals /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/ rake/rake_test_loader.rb" "test/functional/users_controller_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/ rake_test_loader Started F...... Finished in 0.618077 seconds. 1) Failure: test_should_create_user(UsersControllerTest) [/test/functional/ users_controller_test.rb:16]: "User.count" didn't change by 1. <3> expected but was <2>. 7 tests, 9 assertions, 1 failures, 0 errors rake aborted! Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...] (See full trace by running task with --trace) 116
  • 154.
  • 155.
    kiwitter $ raketest:functionals /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/ gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/ functional/users_controller_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/ lib/rake/rake_test_loader Started ....... Finished in 0.883527 seconds. 7 tests, 10 assertions, 0 failures, 0 errors 118
  • 156.
  • 157.
    kiwitter $ script/generatecontroller sessions new exists app/controllers/ exists app/helpers/ create app/views/sessions exists test/functional/ exists test/unit/helpers/ create app/controllers/sessions_controller.rb create test/functional/sessions_controller_test.rb create app/helpers/sessions_helper.rb create test/unit/helpers/sessions_helper_test.rb create app/views/sessions/new.html.erb 120
  • 158.
  • 159.
  • 160.
    kiwitter $ raketest:functionals /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/ rake_test_loader.rb" "test/functional/sessions_controller_test.rb" "test/functional/ users_controller_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader Started F....... Finished in 0.842942 seconds. 1) Failure: test_should_authenticate_user(SessionsControllerTest) [/test/functional/ sessions_controller_test.rb:8]: <nil> expected to not be nil. assert_not_nil 8 tests, 12 assertions, 1 failures, 0 errors assigns(:user) rake aborted! Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...] (See full trace by running task with --trace) 123
  • 161.
  • 162.
    kiwitter $ raketest:functionals /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/ lib/rake/rake_test_loader.rb" "test/functional/sessions_controller_test.rb" "test/functional/users_controller_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/ rake_test_loader Started F....... Finished in 0.57468 seconds. assert_template "users/home" 1) Failure: test_should_authenticate_user(SessionsControllerTest) [/test/functional/ sessions_controller_test.rb:13]: expecting <"users/home"> but rendering with <"sessions/create.html.erb"> 8 tests, 13 assertions, 1 failures, 0 errors rake aborted! Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...] (See full trace by running task with --trace) 125
  • 163.
  • 164.
    kiwitter $ raketest:functionals /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/ rake/rake_test_loader.rb" "test/functional/sessions_controller_test.rb" "test/ functional/users_controller_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/ rake_test_loader Started F....... inconsistência Finished in 0.610806 seconds. 1) Failure: test_should_authenticate_user(SessionsControllerTest) [/test/functional/ sessions_controller_test.rb:9]: Expected response to be a <:success>, but was <302> 8 tests, 11 assertions, 1 failures, 0 errors rake aborted! Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...] (See full trace by running task with --trace) 127
  • 165.
  • 166.
    kiwitter $ raketest:functionals /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/ rake/rake_test_loader.rb" "test/functional/sessions_controller_test.rb" "test/ functional/users_controller_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/ rake_test_loader Started redirect não implica na F....... renderização da página de Finished in 0.99891 seconds. destino 1) Failure: test_should_authenticate_user(SessionsControllerTest) [/test/functional/ sessions_controller_test.rb:13]: expecting <"users/home"> but rendering with <""> 8 tests, 13 assertions, 1 failures, 0 errors rake aborted! Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...] (See full trace by running task with --trace) 129
  • 167.
  • 168.
    kiwitter alegomes$ raketest:functionals /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/ gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/ functional/sessions_controller_test.rb" "test/functional/ users_controller_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/ lib/rake/rake_test_loader Started ........ Finished in 0.547148 seconds. 8 tests, 12 assertions, 0 failures, 0 errors 131
  • 169.
    Labs Testar/implementar autenticação de usuário inválido @user não deve ser criada usuário deve ser redirecionado para página de login Testar/implementar post de mensagem 132
  • 170.
  • 171.
    Req Controller 1 ReqController 2 Req Controller 3 ? 134
  • 172.
  • 173.
    Integração desenvolvedores X linguagem ruby Aceitação clientes linguagem natural 136
  • 174.
  • 175.
    {post, get, delete...}_via_redirect segue todos os redirects follow_redirect! segue apenas um redirect redirect? verifica se a última req foi redirect https! faz com que todas as reqs pareçam HTTPs host! altera o servidor da app 138
  • 176.
  • 177.
    kiwitter $ script/generateintegration_test post_updates exists test/integration/ create test/integration/post_updates_test.rb 140
  • 178.
  • 179.
    kiwitter $ raketest:integration /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/ gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/ integration/post_updates_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/ lib/rake/rake_test_loader Started . Finished in 0.255598 seconds. 1 tests, 2 assertions, 0 failures, 0 errors 142
  • 180.
    Lab? 143
  • 181.
  • 182.
  • 183.
  • 184.
    assert_select("form") verifica a existência da tag <form> <span>Maré de Agilidade</span> assert_select("span", "Maré de Agilidade") assert_select("span", /Agilidade/) 147
  • 185.
  • 186.
  • 187.
  • 188.
    kiwitter $ raketest:integration /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/ gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/ integration/post_updates_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/ lib/rake/rake_test_loader Started . Finished in 0.943481 seconds. 1 tests, 3 assertions, 0 failures, 0 errors 151
  • 189.
    1) Failure: test_should_post_an_update(PostUpdatesTest) [/test/ integration/post_updates_test.rb:15]: Expectedat least 1 element matching "div#welcome_messageeeeeeeee", found 0. <false> is not true. 1 tests, 3 assertions, 1 failures, 0 errors 152
  • 190.
    Testes dos ViewHelpers 153
  • 191.
  • 192.
  • 193.
  • 194.
    kiwitter $ raketest:units /opt/local/bin/ruby -I"lib:test" "/opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/ rake_test_loader.rb" "test/unit/helpers/sessions_helper_test.rb" "test/unit/helpers/ updates_helper_test.rb" "test/unit/helpers/users_helper_test.rb" "test/unit/ update_test.rb" "test/unit/user_test.rb" Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader Started .......E Finished in 0.510089 seconds. 1) Error: test_should_display_user_greetings(UsersHelperTest): NoMethodError: undefined method `display_greetings' for #<UsersHelperTest: 0x1ba7e84> /test/unit/helpers/users_helper_test.rb:10:in `test_should_display_user_greetings' 8 tests, 8 assertions, 0 failures, 1 errors rake aborted! Command failed with status (1): [/opt/local/bin/ruby -I"lib:test" "/opt/loc...] (See full trace by running task with --trace) 157
  • 195.
    8 tests, 9assertions, 0 failures, 0 errors 158
  • 196.
  • 197.
  • 198.
    ActionController::Assertions::RoutingAssertions assert_generates assert_generates "/items", :controller=> "items", :action => "index" assert_recognizes assert_recognizes {:controller => 'items', :action => 'create'}, {:path => 'items', :method => :post} assert_routing assert_routing '/home', :controller => 'home', :action => 'index' http://api.rubyonrails.org/classes/ActionController/Assertions/RoutingAssertions.html 161
  • 199.
    Labs View View Helper Routes 162
  • 200.
  • 201.
    Quem não temcão... 164
  • 202.
  • 203.
    Objeto real indisponívelou de difícil acesso. Reprodução de cenários complexos. 166
  • 204.
    Mocks Aren't Stubs Theterm 'Mock Objects' has become a popular one to describe special case objects that mimic real objects for testing. Most language environments now have frameworks that make it easy to create mock objects. What's often not realized, however, is that mock objects are but one form of special case test object, one that enables a different style of testing. In this article I'll explain how mock objects work, how they encourage testing based on behavior verification, and how the community around them uses them to develop a different style of testing. http://www.martinfowler.com/articles/mocksArentStubs.html 167
  • 205.
    Stu 168
  • 206.
    Objeto falso queretorna um valor predeterminado para uma chamada de método objeto.stubs(:metodo).and_returns("alguma coisa") “ignore a implementacao real de objeto.metodo e retorne ‘alguma coisa’” se objeto.metodo for invocado retornará "alguma coisa" se objeto.metodo NÃO for invocado nada acontecerá 169
  • 207.
  • 208.
    17 tests, 28assertions, 0 failures, 0 errors 171
  • 209.
    17 tests, 26assertions, 1 failures, 0 errors 172
  • 210.
  • 211.
    semelhante ao stub, com uma diferença objeto.stubs(:metodo).adn_returns("alguma coisa") se objeto.metodo for invocado retornará "alguma coisa" se objeto.metodo NÃO for invocado o teste falhará 174
  • 212.
    1) Failure: test_mock_example(UserTest) [/test/unit/user_test.rb:35]: notall expectations were satisfied unsatisfied expectations: - expected exactly once, not yet invoked: #<Mock:0x1884090>.email(any_parameters) satisfied expectations: - expected exactly once, already invoked once: #<Mock:0x1884090>.login(any_parameters) 9 tests, 12 assertions, 1 failures, 0 errors rake aborted! 175
  • 213.
    9 tests, 13assertions, 0 failures, 0 errors 176
  • 214.
    mocks returns raises any_instance with pattern matches 177
  • 215.
    User.any_instance.expects(:login).returns(nil) user.logindeve ser executado apenas uma única vez 178
  • 216.
  • 217.
    http://flexmock.rubyforge.org http://mocha.rubyforge.org http://double-ruby.rubyforge.org http://rspec.info 180
  • 218.
  • 219.
  • 220.
    context setupdo @u = .... end should “alguma coisa” do assert.... end end 183
  • 221.
    $ sudo geminstall thoughtbot-shoulda --source=http://gems.github.com Password: Successfully installed thoughtbot-shoulda-2.10.2 1 gem installed Installing ri documentation for thoughtbot-shoulda-2.10.2... Installing RDoc documentation for thoughtbot-shoulda-2.10.2... http://wiki.github.com/thoughtbot/shoulda/installation 184
  • 222.
  • 223.
  • 224.
    assert_accepts assert_contains assert_does_not_contain assert_rejects assert_same_elements http://dev.thoughtbot.com/shoulda/classes/Shoulda/Assertions.html 187
  • 225.
  • 226.
  • 227.
  • 228.
    should_change should_render_without_layout should_not_change should_respond_with should_assign_to should_respond_with_content_type should_filter_params should_return_from_session should_not_assign_to should_route should_not_set_the_flash should_set_session should_redirect_to should_set_the_flash_to should_render_template should_render_a_form should_render_with_layout should_render_page_with_metadata http://dev.thoughtbot.com/shoulda/classes/Shoulda/Macros.html http://dev.thoughtbot.com/shoulda/classes/Shoulda/ActionController/Macros.html http://dev.thoughtbot.com/shoulda/classes/Shoulda/ActionView/Macros.html 191
  • 229.
    should_allow_mass_assignment_of should_have_named_scope should_allow_values_for should_have_one should_belong_to should_have_readonly_attributes should_ensure_length_at_least should_not_allow_mass_assignment_of should_ensure_length_in_range should_not_allow_values_for should_ensure_length_is should_only_allow_numeric_values_for should_ensure_value_in_range should_protect_attributes should_have_and_belong_to_many should_require_acceptance_of should_have_class_methods should_require_attributes should_have_db_column should_require_unique_attributes should_have_db_columns should_validate_acceptance_of should_have_index should_validate_numericality_of should_have_indices should_validate_presence_of should_have_instance_methods should_validate_uniqueness_of should_have_many http://dev.thoughtbot.com/shoulda/classes/Shoulda/ActiveRecord/Macros.html 192
  • 230.
  • 231.
    194 “ RSpec is the original Behaviour Driven Development framework for Ruby. http://rspec.info
  • 232.
    Test Driven * corretude qualidade < 100% = 100% rebola a ordem não no mato importa 195
  • 233.
    testes passado descrição de algo pronto X especificação futuro descrição de algo inexistente 196
  • 234.
    $ sudo geminstall rspec Password: ************************************************** Thank you for installing rspec-1.2.8 Please be sure to read History.rdoc and Upgrade.rdoc for useful information about this release. ************************************************** Successfully installed rspec-1.2.8 1 gem installed Installing ri documentation for rspec-1.2.8... Installing RDoc documentation for rspec-1.2.8... (...) 197
  • 235.
    kiwitter_rspec $ script/generaterspec exists lib/tasks create lib/tasks/rspec.rake create script/autospec create script/spec create script/spec_server exists spec create spec/rcov.opts create spec/spec.opts create spec/spec_helper.rb 198
  • 236.
    kiwitter_rspec $ rake-T rake spec rake spec:plugin_doc rake spec:clobber_rcov rake spec:plugins rake spec:controllers rake spec:plugins:rspec_on_rails rake spec:db:fixtures:load rake spec:rcov rake spec:doc rake spec:server:restart rake spec:helpers rake spec:server:start rake spec:integration rake spec:server:status rake spec:lib rake spec:server:stop rake spec:models rake spec:views 199
  • 237.
    describe funcionalidade it “should do A” do ... end it “should do B” do actual.should expected end ... end 200
  • 238.
  • 239.
  • 240.
    should_not should have_at_most should be_true be_instance_of have_exactly should be_false should_not helper should be_nil be_an_instance_of should include should should be_close should_not include be_[arbitrary_predicate] should_not be_close inspect_object should_not be_nil be_instance_of should match should_not be_kind_of should_not match be_[arbitrary_predicate] should change should raise_error be_a should_not change should_not raise_error should be_kind_of should eql should respond_to should be_a_kind_of should_not eql should_not respond_to should_not be_kind_of should equal should satisfy should_not should_not equal should_not satisfy be_a_kind_of should exist simple_matcher be_an should_not exist should throw_symbol should be_instance_of should have should_not should should_not have throw_symbol be_an_instance_of should have_at_least wrap_expectation http://rspec.rubyforge.org/rspec/1.2.8/classes/Spec/Matchers.html 203
  • 241.
    expected.XXXXX? expected.should be_XXXXX expected.should be_a_XXXXX expected.shouldbe_an_XXXXX expected.should have_key(:k) expected.has_key?(:k) expected.should have(10).items expected.should have(10).laranjas expected.should have(10).filhos 204
  • 242.
  • 243.
  • 244.
    $ sudo geminstall rspec-rails Password: ************************************************** Thank you for installing rspec-rails-1.2.7.1 If you are upgrading, do this in each of your rails apps that you want to upgrade: $ ruby script/generate rspec Please be sure to read History.rdoc and Upgrade.rdoc for useful information about this release. ************************************************** Successfully installed rspec-rails-1.2.7.1 1 gem installed Installing ri documentation for rspec-rails-1.2.7.1... Installing RDoc documentation for rspec-rails-1.2.7.1... (...) 207
  • 245.
    $ rails kiwitter_rspec create create app/controllers create app/helpers create app/models create app/views/layouts create config/environments create config/initializers create config/locales create db create doc (...) 208
  • 246.
    kiwitter_rspec $ script/generaterspec_scaffold user login:string password:string email:string (...) create spec/controllers/ create spec/routing/ create spec/models/ create spec/helpers/ create spec/fixtures/ create spec/views/users create spec/integration/ (...) create spec/views/users/new.html.erb_spec.rb create spec/views/users/show.html.erb_spec.rb create spec/integration/users_spec.rb create db/migrate create db/migrate/20090802144903_create_users.rb route map.resources :users 209
  • 247.
    script/generate rspec_scaffold update user:references message:text script/generate migration update_user_join 210
  • 248.
    Mais testes gerados queo tradicional Test::Unit 211
  • 249.
  • 250.
  • 251.
  • 252.
    Controller Spec response.should response.should_not { be_success be_redirect redirect_to(url ou hash) render_template(‘users/home’) 215
  • 253.
  • 254.
    View Spec Test::Unit RSpec assigns(@user) assigns[:user] session[:user_id] session[:user_id] cookies[“user_id”] cookies[“user_id”] flash[:notice] flash[:notice] 217
  • 255.
    View Spec { be_valid have_rjs response.should have_tag response.should_not have_text have_text send_email response.should have_tag “xxx” do ... end { with_encoded with_tag without_tag http://rspec.rubyforge.org/rspec-rails/1.2.7.1/classes/Spec/Rails/Matchers.html 218
  • 256.
  • 257.
  • 258.
    { spec spec:controllers spec:helpers spec:integration rake spec:lib spec:models spec:plugins spec:views 221
  • 259.
    kiwitter_rspec $ rakespec:models .. Finished in 1.703168 seconds 2 examples, 0 failures 222
  • 260.
    Lab 223
  • 261.
    faker Faker (...)is used to easily generate fake data http://faker.rubyforge.org 224
  • 262.
    kiwitter $ sudogem install faker Password: Successfully installed faker-0.3.1 1 gem installed Installing ri documentation for faker-0.3.1... Installing RDoc documentation for faker-0.3.1... 225
  • 263.
  • 264.
    Maida McDermott April Metz RowenaJakubowski Anita Lueilwitz Alena Ferry 227
  • 265.
  • 266.
    puts Faker::Lorem.paragraphs(2) Rerum quoshic et. Autem harum ea asperiores consequatur libero et. Ipsum cumque dicta optio voluptate. Et quia officia minus iure vitae. Ducimus delectus unde neque odio voluptas inventore minima. Fugiat nihil error incidunt nihil quo natus omnis. Quis consequatur aut totam ad. Doloribus nihil officiis nobis rerum tempora. Nam eos mollitia delectus assumenda veritatis. Itaque voluptatem repudiandae odit provident error ut. Perspiciatis est facilis sit quis et qui vel. Hic corrupti recusandae aliquid possimus. Et error ad ut voluptatem non labore. Accusantium non tempore aut assumenda architecto enim. Quasi eos et dicta. Tempore quia optio eos pariatur fugiat. Est neque molestias aliquid et. Dolor cum nemo tempora. Eum ratione esse quam magni officiis dolor. Earum maxime sit eaque optio laboriosam tempora voluptatibus. Quo illum ipsa sit. Ea sequi id et sunt nemo quibusdam maxime. Ab voluptate nesciunt maxime rerum iure explicabo in. Sed quidem dignissimos est officia necessitatibus sed qui. Similique odit qui id nostrum corporis autem quas enim. Sunt placeat eum architecto tempora non. Est libero aut repellat mollitia. Quisquam non quia et id est repellat qui aspernatur. Animi ut sit quaerat. Dignissimos enim esse autem qui sed aut optio a. Debitis facilis aut eaque alias exercitationem quia impedit. Maiores vitae id odio est inventore. Aut accusamus et et vel sint. Quo ducimus dolor nemo quia libero autem. Assumenda est voluptas debitis in libero. Illo sit deleniti tenetur nisi. Reiciendis et odit fugiat velit hic. Quo nisi deserunt sit. 229
  • 267.
    http://faker.rubyforge.org/rdoc Array rand shuffle Faker::Address city city_prefixcity_suffix secondary_address street_address street_name street_suffix uk_country uk_county uk_postcode us_state us_state_abbr zip_code Faker::Company bs catch_phrase name suffix Faker::Internet domain_name domain_suffix domain_word email free_email user_name Faker::Lorem paragraph paragraphs sentence sentences words Faker::Name first_name last_name name prefix suffix Faker::PhoneNumber phone_number 230
  • 268.
  • 269.
  • 270.
  • 271.
    DSL features scenarios Rails Test steps Rails Code 233
  • 272.
    $ sudo geminstall cucumber Password: Successfully installed term-ansicolor-1.0.4 Successfully installed polyglot-0.2.6 Successfully installed treetop-1.3.0 Successfully installed diff-lcs-1.1.2 Successfully installed builder-2.1.2 Successfully installed cucumber-0.3.92 6 gems installed Installing ri documentation for term-ansicolor-1.0.4... Installing ri documentation for polyglot-0.2.6... Installing ri documentation for treetop-1.3.0... (...) Installing RDoc documentation for diff-lcs-1.1.2... Installing RDoc documentation for builder-2.1.2... Installing RDoc documentation for cucumber-0.3.92... 234
  • 273.
    kiwitter $ script/plugininstall git://github.com/brynary/webrat.git Initialized empty Git repository in .../kiwitter/vendor/plugins/webrat/.git/ remote: Counting objects: 275, done. remote: Compressing objects: 100% (236/236), done. remote: Total 275 (delta 36), reused 170 (delta 20) Receiving objects: 100% (275/275), 5.07 MiB | 154 KiB/s, done. Resolving deltas: 100% (36/36), done. From git://github.com/brynary/webrat * branch HEAD -> FETCH_HEAD = Webrat - Ruby Acceptance Testing for Web applications ... == Description Webrat lets you quickly write expressive and robust acceptance tests for a Ruby web application. 235
  • 274.
    kiwitter $ sudogem install nokogiri Building native extensions. This could take a while... Successfully installed nokogiri-1.3.3 1 gem installed Installing ri documentation for nokogiri-1.3.3... Installing RDoc documentation for nokogiri-1.3.3... 236
  • 275.
    kiwitter $ script/generatecucumber create features/step_definitions create features/step_definitions/webrat_steps.rb create config/environments/cucumber.rb create features/support create features/support/env.rb create features/support/paths.rb exists lib/tasks create lib/tasks/cucumber.rake create script/cucumber 237
  • 276.
    Feature: caso deuso/estória em teste In order objetivo da funcionalidade Stakeholder o que o stakeholder deseja Background Given pré-condições And mais pré-condições | login | email | password | | alegomes | alegomes@gmail.com | ale123 | | luciana | lu@brasilia.net | xuxu | Scenario: cenário/fluxo em teste Given pré-condições When ação do usuário Then resultado da ação do usuário 238
  • 277.
    kiwitter $ script/generatefeature users_and_updates exists features/step_definitions create features/manage_users_and_updates.feature create features/step_definitions/users_and_updates_steps.rb 239
  • 278.
  • 279.
    Teste de aceitação geradopelo Cucumber 241
  • 280.
    modificado para okiwitter 242
  • 281.
    kiwitter $ rakefeatures /opt/local/bin/ruby -I "/opt/local/lib/ruby/gems/1.8/gems/cucumber-0.3.92/lib:lib" "/opt/local/lib/ ruby/gems/1.8/gems/cucumber-0.3.92/bin/cucumber" --format pretty features/ manage_users_and_updates.feature Feature: Post update messages In order to make my life widely public As a User I want to post short messages describing what I am doing Scenario: Post new messages # features/manage_users_and_updates.feature:6 Given I am at users home page # features/manage_users_and_updates.feature:7 And I have entered a text message up to 140 chars # features/manage_users_and_updates.feature:8 When I press post # features/manage_users_and_updates.feature:9 Then the message should be registered # features/manage_users_and_updates.feature:10 1 scenario (1 undefined) 4 steps (4 undefined) 0m0.653s ... 243
  • 282.
    ... You can implementstep definitions for undefined steps with these snippets: Given /^I am at users home page$/ do pending end Given /^I have entered a text message up to 140 chars$/ do pending end When /^I press post$/ do pending end Then /^the message should be registered$/ do pending end 244
  • 283.
  • 284.
  • 285.
    ... You can implementstep definitions for undefined steps with these snippets: Given /^I am at users home page$/ do pending end Given /^I have entered a text message up to 140 chars$/ do pending end When /^I press post$/ do pending end Then /^the message should be registered$/ do pending end 247
  • 286.
    kiwitter $ rakefeatures /opt/local/bin/ruby -I "/opt/local/lib/ruby/gems/1.8/gems/cucumber-0.3.92/lib:lib" "/opt/ local/lib/ruby/gems/1.8/gems/cucumber-0.3.92/bin/cucumber" --format pretty features/ manage_users_and_updates.feature Feature: Post update messages In order to make my life widely public As a User I want to post short messages describing what I am doing Scenario: Post new messages Given I am at users home page TODO (Cucumber::Pending) features/manage_users_and_updates.feature:7:in `Given I am at users home page' And I have entered a text message up to 140 chars When I press post Then the message should be registered 1 scenario (1 pending) 4 steps (3 skipped, 1 pending) 0m0.134s 248
  • 287.
    Given I amat users home page TODO (Cucumber::Pending) features/manage_users_and_updates.feature:7:in `Given I am at users home page' Given /^I am at users home page$/ do visit "users/home" end 249
  • 288.
    kiwitter $ rakefeatures ... Scenario: Post new messages users_controller.home Given I am at users home page And I have entered a text message up to 140 chars TODO (Cucumber::Pending) features/manage_users_and_updates.feature:8:in `And I have entered a text message up to 140 chars' When I press post Then the message should be registered 1 scenario (1 pending) 4 steps (2 skipped, 1 pending, 1 passed) 0m0.260s 250
  • 289.
    And I haveentered a text message up to 140 chars TODO (Cucumber::Pending) features/manage_users_and_updates.feature:8:in `And I have entered a text message up to 140 chars' 251
  • 290.
    kiwitter $ cucumberfeatures/manage_users_and_updates.feature Feature: Post update messages In order to make my life widely public As a User I want to post short messages describing what I am doing Scenario: Post new messages users_controller.home Given I am at users home page And I have entered a text message up to 140 chars When I press post TODO (Cucumber::Pending) features/manage_users_and_updates.feature:9:in `When I press post' Then the message should be registered 1 scenario (1 pending) 4 steps (1 skipped, 1 pending, 2 passed) 0m0.305s 252
  • 291.
    When I presspost TODO (Cucumber::Pending) features/manage_users_and_updates.feature:9:in `When I press post' 253
  • 292.
    kiwitter $ cucumberfeatures/manage_users_and_updates.feature Feature: Post update messages In order to make my life widely public As a User I want to post short messages describing what I am doing Scenario: Post new messages users_controller.home Given I am at users home page And I have entered a text message up to 140 chars When I press post Then the message should be registered TODO (Cucumber::Pending) features/manage_users_and_updates.feature:10:in `Then the message should be registered' 1 scenario (1 pending) 4 steps (1 pending, 3 passed) 0m0.282s 254
  • 293.
    Then the messageshould be registered TODO (Cucumber::Pending) features/manage_users_and_updates.feature:10:in `Then the message should be registered' ? 255
  • 294.
    webrat http://github.com/brynary/webrat/tree/master 256
  • 295.
    kiwitter $ script/plugininstall git://github.com/brynary/webrat.git Initialized empty Git repository in .../kiwitter/vendor/plugins/webrat/.git/ remote: Counting objects: 275, done. remote: Compressing objects: 100% (236/236), done. remote: Total 275 (delta 36), reused 170 (delta 20) Receiving objects: 100% (275/275), 5.07 MiB | 125 KiB/s, done. Resolving deltas: 100% (36/36), done. From git://github.com/brynary/webrat * branch HEAD -> FETCH_HEAD (= Webrat - Ruby Acceptance Testing for Web applications - http://gitrdoc.com/brynary/webrat - http://groups.google.com/group/webrat - http://webrat.lighthouseapp.com/ - http://github.com/brynary/webrat - #webrat on Freenode (...) 257
  • 296.
  • 297.
  • 298.
  • 299.
    $ sudo geminstall rcov Password: Building native extensions. This could take a while... Successfully installed rcov-0.8.1.2.0 1 gem installed Installing ri documentation for rcov-0.8.1.2.0... Installing RDoc documentation for rcov-0.8.1.2.0... 261
  • 300.
    $ rcov --version rcov0.8.1.2 2007-11-22 262
  • 301.
    kiwitter $ ./script/plugininstall --force http://svn.codahale.com/rails_rcov + ./MIT-LICENSE + ./README + ./tasks/rails_rcov.rake http://agilewebdevelopment.com/plugins/rails_rcov 263
  • 302.
    kiwitter $ rake-T | grep rcov rake doc:plugins:rails_rcov rake test:profile:clobber_rcov rake spec:clobber_rcov rake test:profile:rcov rake spec:rcov rake test:recent:clobber_rcov rake test:benchmark:clobber_rcov rake test:recent:rcov rake test:benchmark:rcov rake test:test:clobber_rcov rake test:functionals:clobber_rcov rake test:test:rcov rake test:functionals:rcov rake test:uncommitted:clobber_rcov rake test:integration:clobber_rcov rake test:uncommitted:rcov rake test:integration:rcov rake test:units:clobber_rcov rake test:plugins:clobber_rcov rake test:units:rcov rake test:plugins:rcov 264
  • 303.
    kiwitter $ raketest:units:rcov 10 tests, 13 assertions, 1 failures, 1 errors +----------------------------------------------------+-------+-------+--------+ | File | Lines | LOC | COV | +----------------------------------------------------+-------+-------+--------+ |.../ruby/1.8/gems/sqlite3-ruby-1.2.5/lib/sqlite3.rb | 1 | 1 | 100.0% | |...gems/sqlite3-ruby-1.2.5/lib/sqlite3/constants.rb | 49 | 44 | 97.7% | |.../gems/sqlite3-ruby-1.2.5/lib/sqlite3/database.rb | 721 | 340 | 40.3% | |...3-ruby-1.2.5/lib/sqlite3/driver/native/driver.rb | 219 | 180 | 48.3% | |....8/gems/sqlite3-ruby-1.2.5/lib/sqlite3/errors.rb | 68 | 58 | 84.5% | |...8/gems/sqlite3-ruby-1.2.5/lib/sqlite3/pragmas.rb | 271 | 190 | 45.8% | |...gems/sqlite3-ruby-1.2.5/lib/sqlite3/resultset.rb | 180 | 114 | 72.8% | |...gems/sqlite3-ruby-1.2.5/lib/sqlite3/statement.rb | 231 | 128 | 50.0% | |...ems/sqlite3-ruby-1.2.5/lib/sqlite3/translator.rb | 109 | 64 | 20.3% | |...1.8/gems/sqlite3-ruby-1.2.5/lib/sqlite3/value.rb | 57 | 44 | 29.5% | |app/controllers/application_controller.rb | 48 | 21 | 23.8% | |app/controllers/sessions_controller.rb | 32 | 9 | 22.2% | |app/controllers/updates_controller.rb | 85 | 60 | 13.3% | |app/controllers/users_controller.rb | 89 | 63 | 14.3% | |app/helpers/application_helper.rb | 3 | 2 | 100.0% | |app/helpers/sessions_helper.rb | 3 | 2 | 100.0% | |app/helpers/updates_helper.rb | 2 | 2 | 100.0% | |app/helpers/users_helper.rb | 8 | 5 | 40.0% | |app/models/update.rb | 5 | 4 | 100.0% | |app/models/user.rb | 8 | 6 | 100.0% | +----------------------------------------------------+-------+-------+--------+ |Total | 2189 | 1337 | 46.3% | 265 +----------------------------------------------------+-------+-------+--------+
  • 304.
  • 305.

Editor's Notes

  • #4 Pouco tempo e muito conte&amp;#xFA;do Turma heterog&amp;#xEA;nea Cada um segue seu ritmo Pouca teoria e muita pr&amp;#xE1;tica
  • #9 Comecemos falando de testes
  • #10 Se voc&amp;#xEA; falar com qualquer pessoa comum sobre testes, ela associar&amp;#xE1; &amp;#xE0; realiza&amp;#xE7;&amp;#xE3;o de rotinas de verifica&amp;#xE7;&amp;#xE3;o de algo anteriormente constru&amp;#xED;do.
  • #11 Se voc&amp;#xEA; falar com qualquer pessoa comum sobre testes, ela associar&amp;#xE1; &amp;#xE0; realiza&amp;#xE7;&amp;#xE3;o de rotinas de verifica&amp;#xE7;&amp;#xE3;o de algo anteriormente constru&amp;#xED;do.
  • #12 O problema, entretanto, &amp;#xE9; grande tempo entre a constru&amp;#xE7;&amp;#xE3;o e a verifica&amp;#xE7;&amp;#xE3;o.
  • #13 O problema, entretanto, &amp;#xE9; grande tempo entre a constru&amp;#xE7;&amp;#xE3;o e a verifica&amp;#xE7;&amp;#xE3;o.
  • #14 O problema, entretanto, &amp;#xE9; grande tempo entre a constru&amp;#xE7;&amp;#xE3;o e a verifica&amp;#xE7;&amp;#xE3;o.
  • #15 A medida que o tempo passa, manuten&amp;#xE7;&amp;#xF5;es ficam mais caras.
  • #16 E a&amp;#xED;, o cen&amp;#xE1;rio mais comum, e come&amp;#xE7;ar a guerra fria entre os que constroem e os que verificam.
  • #17 Convergindo na pior afirma&amp;#xE7;&amp;#xE3;o de qualquer membro de equipe: &amp;#x201C;n&amp;#xE3;o &amp;#xE9; problema meu&amp;#x201D;
  • #18 Como forma de aliviar, dentre outras coisas, essa disputa entre desenvolvedores e testadores, foi proposta uma metodologia de desenvolvimento chamada TDD.
  • #19 Quando se faz teste, al&amp;#xE9;m do c&amp;#xF3;digo programa em si, deve-se escrever outro c&amp;#xF3;digo que verifique o programa que, quando &amp;#xE9; executado....
  • #20 Quando se faz teste, al&amp;#xE9;m do c&amp;#xF3;digo programa em si, deve-se escrever outro c&amp;#xF3;digo que verifique o programa que, quando &amp;#xE9; executado....
  • #21 ...pode passar...
  • #45 Eu tenho um c&amp;#xF3;digo e v&amp;#xE1;rios testes que o suportam.
  • #46 Eu tenho um c&amp;#xF3;digo e v&amp;#xE1;rios testes que o suportam.
  • #47 Eu tenho um c&amp;#xF3;digo e v&amp;#xE1;rios testes que o suportam.
  • #48 Eu tenho um c&amp;#xF3;digo e v&amp;#xE1;rios testes que o suportam.
  • #49 Eu tenho um c&amp;#xF3;digo e v&amp;#xE1;rios testes que o suportam.
  • #50 Eu tenho um c&amp;#xF3;digo e v&amp;#xE1;rios testes que o suportam.
  • #51 Eu tenho um c&amp;#xF3;digo e v&amp;#xE1;rios testes que o suportam.
  • #52 Eu tenho um c&amp;#xF3;digo e v&amp;#xE1;rios testes que o suportam.
  • #53 O impacto de qualquer modifica&amp;#xE7;&amp;#xE3;o no c&amp;#xF3;digo....
  • #54 ...&amp;#xE9; imediatamente apontado por seus testes.
  • #55 Testes automaticos tratam de algo t&amp;#xE3;o importante que mal sabemos traduzir....
  • #56 Controla o crescimento do custo das mudan&amp;#xE7;as que, tradicionalmente, &amp;#xE9; descontrolado.
  • #71 Iterativo vs Incremental Iterativo!??! S&amp;#xF3; na constru&amp;#xE7;&amp;#xE3;o. Big Design Upfront vs Design Evolutivo
  • #72 Iterativo vs Incremental Iterativo!??! S&amp;#xF3; na constru&amp;#xE7;&amp;#xE3;o. Big Design Upfront vs Design Evolutivo
  • #73 Big design upf-ront
  • #101 Mudan&amp;#xE7;as: rastreamento autom&amp;#xE1;tico de impactos de modifica&amp;#xE7;&amp;#xF5;es Robustez: evitar apps fr&amp;#xE1;geis cujos bugs sempre voltam Direcionamento: &amp;#x201C;s&amp;#xED;ndrome da folha em branco&amp;#x201D;
  • #105 Vamos fazer um Twitter.
  • #111 Quando se cria uma app Rails, v&amp;#xE1;rios testes s&amp;#xE3;o automaticamente gerados...
  • #112 Para execu&amp;#xE7;&amp;#xE3;o dos teste, utiliza-se instru&amp;#xE7;&amp;#xF5;es rake.
  • #113 Quando se executa os tese
  • #116 Toda execu&amp;#xE7;&amp;#xE3;o de testes no Rails utiliza o seu ambiente de testes, sem impactar na base de desenvolvimento ou nos dados de produ&amp;#xE7;&amp;#xE3;o.
  • #118 Fixtures &amp;#xE9; o mecanismo do Rails para cria&amp;#xE7;&amp;#xE3;o da massa de testes.
  • #119 Na verdade, Fixtures &amp;#xE9; uma t&amp;#xE9;cnica n&amp;#xE3;o exclusiva do Rails
  • #120 ...discutida at&amp;#xE9; em livros...
  • #125 Testes unit&amp;#xE1;rios do Rails s&amp;#xE3;o compostos por recursos b&amp;#xE1;sicos de testes do Ruby mais recursos espec&amp;#xED;ficos do Rails
  • #126 O funcionamento dos testes unit&amp;#xE1;rios seguem a regra geral, com detalhe para o passo 3.
  • #127 V&amp;#xE1;rias asser&amp;#xE7;&amp;#xF5;es v&amp;#xEA;m do Ruby Test::Unit::TestCase
  • #128 Do Ruby...
  • #129 Do Rails...
  • #132 Teste gerado pelo Rails.
  • #133 Criemos um teste pra checar o ActiveRecord (apenas para fins did&amp;#xE1;ticos)
  • #134 Oops, tudo funcionou de cara. Mas claro, o ActiveRecord j&amp;#xE1; est&amp;#xE1; pronto!
  • #135 Fa&amp;#xE7;amos um novo teste.
  • #139 TODO: u.valid? u.errors.invalid?(:email) mensagem de erro no assert associacao yml helper
  • #140 Implementar funcionalidade de Login.
  • #143 Defini&amp;#xE7;&amp;#xE3;o do m&amp;#xE9;todo &amp;#x2018;signin&amp;#x2019;
  • #144 O m&amp;#xE9;todo signin retorna &amp;#x2018;null&amp;#x2019;, mas o teste espera &amp;#x2018;true&amp;#x2019;
  • #145 Teste espera &amp;#x2018;false&amp;#x2019; mas c&amp;#xF3;digo retorna &amp;#x2018;true&amp;#x2019;
  • #149 Agora sim. Ficou mais claro qual teste est&amp;#xE1; falhando.
  • #150 N&amp;#xE3;o encontrou no banco qualquer registro com login = &amp;#x201C;alegomes&amp;#x201D; e password = &amp;#x201C;ale123&amp;#x201D;
  • #155 Dicas: - Criar scaffold de updates
  • #164 Resumo dos testes funcionais: teste enviar requisi&amp;#xE7;&amp;#xE3;o HTTP ao controller e verifica se a resposta enviada coincide com a resposta esperada.
  • #165 Testes unit&amp;#xE1;rios do Rails s&amp;#xE3;o compostos por recursos b&amp;#xE1;sicos de testes do Ruby mais recursos espec&amp;#xED;ficos do Rails
  • #166 Novidades
  • #167 Asser&amp;#xE7;&amp;#xF5;es
  • #169 Teste pode passar, mas pode n&amp;#xE3;o existir rota definidar pra ele. Uma par&amp;#xE2;metro n&amp;#xE3;o string pode fazer o teste passar, mas n&amp;#xE3;o funcionar&amp;#xE1; para o usu&amp;#xE1;rio, pois o browser sempre manda string.
  • #170 assert_response {200,300...} ou {:success, :redirect, :missing, :error} assert_template &amp;#x201C;index&amp;#x201D; (n&amp;#xE3;o checa o conte&amp;#xFA;do!) assert_redirect n&amp;#xE3;o segue o redirecionamento
  • #171 Exemplos
  • #172 N&amp;#xE3;o repita os mesmos testes nos dois lugares.
  • #173 Pra cada controlador...
  • #174 ...tem-se seu respectivo teste.
  • #175 Testes funcionais gerados pelo scaffold n&amp;#xE3;o est&amp;#xE3;o passando.
  • #176 A requisi&amp;#xE7;&amp;#xE3;o post est&amp;#xE1; passando um usu&amp;#xE1;rio sem informar nenhum atributo, contrariando nossa valida&amp;#xE7;&amp;#xE3;o.
  • #177 Agora sim!
  • #178 Prossigamos com a funcionaldiade de login.
  • #179 Gera&amp;#xE7;&amp;#xE3;o de um novo controlador de sess&amp;#xF5;es, respons&amp;#xE1;vel pelo login e logout do usu&amp;#xE1;rio.
  • #180 Teste funcional criado para o novo controller.
  • #181 Mais de perto.... Esta &amp;#xE9; a forma mais comum de se testar um controlador: assert_response assert_not_nil assert_template
  • #182 Teste funcional criado falhando na linha 8: assert_not_nil assigns(:user)
  • #183 Controlador invocando Model para autentica&amp;#xE7;&amp;#xE3;o do usu&amp;#xE1;rio e disponibiliza&amp;#xE7;&amp;#xE3;o da inst&amp;#xE2;ncia @user pra camada View.
  • #184 Falha agora no assert da linha 13: assert_template &quot;users/home&quot;
  • #185 Se o usu&amp;#xE1;rio tiver sido autenticado com sucesso, redirecione-o para sua p&amp;#xE1;gina home.
  • #186 Nosso teste est&amp;#xE1; inconsistente! Em um momento, ele verifica o retorno de sucesso (200) da requisi&amp;#xE7;&amp;#xE3;o. Em outro, ele checa se a requisi&amp;#xE7;&amp;#xE3;o gerou um redirecionamento de p&amp;#xE1;gina (300).
  • #187 Mudan&amp;#xE7;a no teste de &amp;#x2018;assert_response :success&amp;#x2019; para &amp;#x2018;assert_response :redirect&amp;#x2019;
  • #188 ATEN&amp;#xC7;&amp;#xC3;O! O redirect n&amp;#xE3;o implica no render do template de destino. Logo, n&amp;#xE3;o podemos usar assert_template com redirect.
  • #189 Mudan&amp;#xE7;as no teste: - Substitui&amp;#xE7;&amp;#xE3;o do assert_template por assert_redirect_to - Elimina&amp;#xE7;&amp;#xE3;o do &amp;#x2018;assert_response :redirect&amp;#x2019;, cuja verifica&amp;#xE7;&amp;#xE3;o j&amp;#xE1; &amp;#xE9; impl&amp;#xED;cita no assert_redirected_to
  • #193 Fa&amp;#xE7;a um monte de chamadas a v&amp;#xE1;rios controladores e verifique o resultado.
  • #194 Tratam de conceitos diferentes.