Rodolfo Carvalho discussed Test-Driven Development (TDD) in Perl. He covered how to write tests first using modules like Test::More and Test::Most, then code to pass the tests. An example was provided of incrementally developing a Fibonacci function using TDD. He also discussed testing web applications with Test::WWW::Mechanize and Test::Mojo. Finally, he promoted regular coding dojos as a way to practice TDD in pairs and learn from others.
9. 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.
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.
}
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;
22. 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
23. 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