Rodolfo Carvalho - @201
   YAPC::Brasil 2011
Rodolfo Carvalho
● Eng. Computação UFRJ
● PythOnRio
● Coding Dojo Rio
● Ex-Globo.com, ex-Intelie
● Entusiasta de Racket
● Monge Perl?
  Quem sabe em breve :P
CPAN: Comprehensive Perl Archive Network
                metacpan.org
Desenvolvimento "tradicional"


  Design


               Code


                            Test
TDD: Test-Driven Development

     Design              Test




               Test


     Refacto
        r                Code
No longo prazo...




              x


                    ...
 tempo
Em Perl
● CPAN contém diversas opções
● TAP: "Test Anything Protocol"
Test::Simple
Test::More + Test::Exception
             Test::Differences
             Test::Deep           + prove
             Test::Warn
          = Test::Most
Exemplo
Problema: calcular o n-ésimo número da
sequência de Fibonacci.

Design: escrever uma função que recebe um
argumento numérico (n) e retorna o número da
sequência correspondente.
Exemplo: Fibonacci
Teste:                   Resultado:
use Test::More;          $ prove fibonacci.pl
                         fibonacci.pl .. Undefined
                         subroutine &main::fibonacci
is( fibonacci(0), 0 );   called at fibonacci.pl line 4.
                         fibonacci.pl .. Dubious, test
                         returned 9 (wstat 2304,
done_testing();          0x900)
Exemplo: Fibonacci
Implementação:    Resultado:
sub fibonacci {   $ prove fibonacci.pl
                  fibonacci.pl .. ok
  return 0;
                  All tests successful.
}
Exemplo: Fibonacci




               ...
Exemplo: Fibonacci
Teste:                   Implementação:
is( fibonacci(0), 0 );   sub fibonacci {
                           my $n = shift;
is( fibonacci(1), 1 );
                           return 0 if $n eq 0;
is( fibonacci(2), 1 );     return 1 if $n eq 1;
                           return 1 if $n eq 2;
                         }
Exemplo: Fibonacci
Teste:                   Resultado:
is( fibonacci(0), 0 );   $ prove fibonacci.pl
                         fibonacci.pl .. 1/?
is( fibonacci(1), 1 );
                         # Failed test at fibonacci.pl
is( fibonacci(2), 1 );   line 15.
is( fibonacci(3), 2 );   #        got: ''
                         # expected: '2'
                         # Looks like you failed 1
                         test of 4.
Exemplo: Fibonacci
Implementação:                Resultado:
sub fibonacci {               $ prove fibonacci.pl
   my $n = shift;             fibonacci.pl .. ok
   return 0 if $n eq 0;       All tests successful.
   return 1 if $n eq 1;
   return fibonacci($n-2) +
           fibonacci($n-1);
}
Exemplo: Fibonacci
Teste:                         Resultado:
my $phi = (1+sqrt 5)/2;        $ prove fibonacci.pl
my $psi = -1/$phi;             fibonacci.pl .. ok
foreach ( 0..20 ) {            All tests successful.
  is( fibonacci($_),
      ($phi**$_ - $psi**$_)/
       sqrt 5 );
}
Perl
oferece muito mais
package Example::Test;
                     use base qw(Test::Class);
                     use Test::More;

OOP's "xUnit"        # setup methods are run before every test method.
                     sub make_fixture : Test(setup) {
                        my $array = [1, 2];
                        shift->{test_array} = $array;

● Test::Class        };

                     # a test method that runs 1 test
                     sub test_push : Test {
                        my $array = shift->{test_array};
                        push @$array, 3;
                        is_deeply($array, [1, 2, 3], 'push worked');
                     };
● Test::MockObject   # a test method that runs 4 tests
                     sub test_pop : Test(4) {
                        my $array = shift->{test_array};
● DBD::Mock             is(pop @$array, 2, 'pop = 2');
                        is(pop @$array, 1, 'pop = 1');
                        is_deeply($array, [], 'array empty');
                        is(pop @$array, undef, 'pop = undef');
● Test::TCP          };

                     # teardown methods are run after every test method.
                     sub teardown : Test(teardown) {
                        my $array = shift->{test_array};
                        diag("array = (@$array) after test(s)");
                     };
TDD + Web
● Test::WWW::Mechanize


       use Test::More tests => 5;
       use Test::WWW::Mechanize;

       my $mech = Test::WWW::Mechanize->new;
       $mech->get_ok( $page );
       $mech->base_is( 'http://petdance.com/', 'Proper <BASE HREF>' );
       $mech->title_is( 'Invoice Status', "Make sure we're on the invoice page" );
       $mech->text_contains( 'Andy Lester', 'My name somewhere' );
       $mech->content_like( qr/(cpan|perl).org/, 'Link to perl.org or CPAN' );
TDD + Web
                    use Test::More tests => 10;

● Test::Mojo        use Test::Mojo;

                    my $t = Test::Mojo->new('MyApp');

                    $t->get_ok('/welcome')
                     ->status_is(200)

HTML5                ->content_like(qr/Hello!/, 'welcome message');

                    $t->post_form_ok('/search', {title => 'Perl', author => 'taro'})
                     ->status_is(200)
                     ->content_like(qr/Perl.+taro/);

Real-time webapps   $t->delete_ok('/something')
                     ->status_is(200)
                     ->header_is('X-Powered-By' => 'Mojolicious (Perl)')
                     ->header_isnt('X-Bender' => 'Bite my shiny metal ass!');
                     ->content_is('Hello world!');

                    $t->websocket_ok('/echo')
                     ->send_message_ok('hello')
                     ->message_is('echo: hello')
                     ->finish_ok;
Test anything...
● Test::Pod::Coverage
● Test::UseAllModules
● Test::NoWarnings
● Test::Perl::Critic
● Test::AskAnExpert
● Test::Inline
● Test::UniqueTestNames
Não basta escrever testes
Fácil:
● Dada uma entrada, comparar saída e saída esperada


Difícil:
● O que testar
● Como testar
● Erros não previstos
Não basta escrever testes
Short list of ways tests could fail without any code change:
 ●   "Temporary" test files and fixtures might be dirty.

 ●   "Temporary" databases and tables might be dirty.

 ●   It is sensitive to time or date.

 ●   It uses network resources and they changed.

 ●   The compiler was changed.

 ●   The installed libraries used were changed.

 ●   The libraries the libraries use were changed.

 ●   The kernel was changed.

 ●   Any servers used (databases, web servers, etc...) were changed.

 ●   It uses parallel processing and a subtle bug only occurs sometimes.

 ●   The disk (or the filesystem where temp files go) is full.

 ●   The disk (or the filesystem where temp files go) is broken.

 ●   Your memory/disk/process/filehandle quotas were reduced.

 ●   The machine has run out of memory.

 ●   The machine has run out of filehandles.

 ●   It uses fixtures with randomly generated data and generated some that tickled a bug.



                                                                                            Michael Schwern
metacpan.org
Quero fazer TDD, e agora?
Coding Dojo
Coding Dojo
● Prática deliberada de TDD
● Programação em par
● Aprendizado coletivo



                              + é divertido!
Como funciona?
     Precisamos de:
● Piloto e co-piloto
● Problema
● Computador
● Projetor
● Cronômetro
● Comida!
5 ~ 7 min
Retrospectiva
Onde




 TDD
  +
 Perl
        Centro, toda quarta-feira às 18:30
                                             UFF - Niterói
         Av Treze de Maio, 13 – sala 616     quintas 19:00
                Edifício Municipal
Agradecimentos
   Breno (Garu)              Dojo Rio




                            dojorio.org




Contato           about.me/rhcarvalho

O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding Dojo tem o resto.

  • 1.
    Rodolfo Carvalho -@201 YAPC::Brasil 2011
  • 2.
    Rodolfo Carvalho ● Eng.Computação UFRJ ● PythOnRio ● Coding Dojo Rio ● Ex-Globo.com, ex-Intelie ● Entusiasta de Racket ● Monge Perl? Quem sabe em breve :P
  • 3.
    CPAN: Comprehensive PerlArchive Network metacpan.org
  • 4.
  • 5.
    TDD: Test-Driven Development Design Test Test Refacto r Code
  • 7.
    No longo prazo... x ... tempo
  • 8.
    Em Perl ● CPANcontém diversas opções ● TAP: "Test Anything Protocol" Test::Simple Test::More + Test::Exception Test::Differences Test::Deep + prove Test::Warn = Test::Most
  • 9.
    Exemplo Problema: calcular on-ésimo número da sequência de Fibonacci. Design: escrever uma função que recebe um argumento numérico (n) e retorna o número da sequência correspondente.
  • 10.
    Exemplo: Fibonacci Teste: Resultado: use Test::More; $ prove fibonacci.pl fibonacci.pl .. Undefined subroutine &main::fibonacci is( fibonacci(0), 0 ); called at fibonacci.pl line 4. fibonacci.pl .. Dubious, test returned 9 (wstat 2304, done_testing(); 0x900)
  • 11.
    Exemplo: Fibonacci Implementação: Resultado: sub fibonacci { $ prove fibonacci.pl fibonacci.pl .. ok return 0; All tests successful. }
  • 12.
  • 13.
    Exemplo: Fibonacci Teste: Implementação: is( fibonacci(0), 0 ); sub fibonacci { my $n = shift; is( fibonacci(1), 1 ); return 0 if $n eq 0; is( fibonacci(2), 1 ); return 1 if $n eq 1; return 1 if $n eq 2; }
  • 14.
    Exemplo: Fibonacci Teste: Resultado: is( fibonacci(0), 0 ); $ prove fibonacci.pl fibonacci.pl .. 1/? is( fibonacci(1), 1 ); # Failed test at fibonacci.pl is( fibonacci(2), 1 ); line 15. is( fibonacci(3), 2 ); # got: '' # expected: '2' # Looks like you failed 1 test of 4.
  • 15.
    Exemplo: Fibonacci Implementação: Resultado: sub fibonacci { $ prove fibonacci.pl my $n = shift; fibonacci.pl .. ok return 0 if $n eq 0; All tests successful. return 1 if $n eq 1; return fibonacci($n-2) + fibonacci($n-1); }
  • 16.
    Exemplo: Fibonacci Teste: Resultado: my $phi = (1+sqrt 5)/2; $ prove fibonacci.pl my $psi = -1/$phi; fibonacci.pl .. ok foreach ( 0..20 ) { All tests successful. is( fibonacci($_), ($phi**$_ - $psi**$_)/ sqrt 5 ); }
  • 17.
  • 18.
    package Example::Test; use base qw(Test::Class); use Test::More; OOP's "xUnit" # setup methods are run before every test method. sub make_fixture : Test(setup) { my $array = [1, 2]; shift->{test_array} = $array; ● Test::Class }; # a test method that runs 1 test sub test_push : Test { my $array = shift->{test_array}; push @$array, 3; is_deeply($array, [1, 2, 3], 'push worked'); }; ● Test::MockObject # a test method that runs 4 tests sub test_pop : Test(4) { my $array = shift->{test_array}; ● DBD::Mock is(pop @$array, 2, 'pop = 2'); is(pop @$array, 1, 'pop = 1'); is_deeply($array, [], 'array empty'); is(pop @$array, undef, 'pop = undef'); ● Test::TCP }; # teardown methods are run after every test method. sub teardown : Test(teardown) { my $array = shift->{test_array}; diag("array = (@$array) after test(s)"); };
  • 19.
    TDD + Web ●Test::WWW::Mechanize use Test::More tests => 5; use Test::WWW::Mechanize; my $mech = Test::WWW::Mechanize->new; $mech->get_ok( $page ); $mech->base_is( 'http://petdance.com/', 'Proper <BASE HREF>' ); $mech->title_is( 'Invoice Status', "Make sure we're on the invoice page" ); $mech->text_contains( 'Andy Lester', 'My name somewhere' ); $mech->content_like( qr/(cpan|perl).org/, 'Link to perl.org or CPAN' );
  • 20.
    TDD + Web use Test::More tests => 10; ● Test::Mojo use Test::Mojo; my $t = Test::Mojo->new('MyApp'); $t->get_ok('/welcome') ->status_is(200) HTML5 ->content_like(qr/Hello!/, 'welcome message'); $t->post_form_ok('/search', {title => 'Perl', author => 'taro'}) ->status_is(200) ->content_like(qr/Perl.+taro/); Real-time webapps $t->delete_ok('/something') ->status_is(200) ->header_is('X-Powered-By' => 'Mojolicious (Perl)') ->header_isnt('X-Bender' => 'Bite my shiny metal ass!'); ->content_is('Hello world!'); $t->websocket_ok('/echo') ->send_message_ok('hello') ->message_is('echo: hello') ->finish_ok;
  • 21.
    Test anything... ● Test::Pod::Coverage ●Test::UseAllModules ● Test::NoWarnings ● Test::Perl::Critic ● Test::AskAnExpert ● Test::Inline ● Test::UniqueTestNames
  • 22.
    Não basta escrevertestes Fácil: ● Dada uma entrada, comparar saída e saída esperada Difícil: ● O que testar ● Como testar ● Erros não previstos
  • 23.
    Não basta escrevertestes Short list of ways tests could fail without any code change: ● "Temporary" test files and fixtures might be dirty. ● "Temporary" databases and tables might be dirty. ● It is sensitive to time or date. ● It uses network resources and they changed. ● The compiler was changed. ● The installed libraries used were changed. ● The libraries the libraries use were changed. ● The kernel was changed. ● Any servers used (databases, web servers, etc...) were changed. ● It uses parallel processing and a subtle bug only occurs sometimes. ● The disk (or the filesystem where temp files go) is full. ● The disk (or the filesystem where temp files go) is broken. ● Your memory/disk/process/filehandle quotas were reduced. ● The machine has run out of memory. ● The machine has run out of filehandles. ● It uses fixtures with randomly generated data and generated some that tickled a bug. Michael Schwern
  • 24.
  • 26.
  • 27.
  • 29.
    Coding Dojo ● Práticadeliberada de TDD ● Programação em par ● Aprendizado coletivo + é divertido!
  • 30.
    Como funciona? Precisamos de: ● Piloto e co-piloto ● Problema ● Computador ● Projetor ● Cronômetro ● Comida!
  • 31.
    5 ~ 7min
  • 32.
  • 33.
    Onde TDD + Perl Centro, toda quarta-feira às 18:30 UFF - Niterói Av Treze de Maio, 13 – sala 616 quintas 19:00 Edifício Municipal
  • 35.
    Agradecimentos Breno (Garu) Dojo Rio dojorio.org Contato about.me/rhcarvalho