Uma das grandes dificuldades de testar uma API remota é reproduzir as requisições HTTP de maneira confiável e estável. Um dos problemas é que as respostas dos serviços mudam, impedindo que os testes contenham valores pré-definidos para a conferência dos resultados da requisição.
Suponha, por exemplo, um cliente mínimo de API da wikipedia:
package Wikipedia::API; use Moose; use JSON; use LWP::UserAgent; has ua => ( is => 'rw', handles => [qw(get)], default => sub { LWP::UserAgent->new; } ); has json => ( is => 'rw', handles => [qw(decode)], default => sub { JSON->new->utf8 } ); around get => sub { my $orig = shift; my $self = shift; my $res = $self->$orig(@_); return $self->decode( $res->content ); }; sub query { my ( $self, $page, $prop ) = @_; my $url = q{http://br.wikipedia.org/w/api.php?format=json&action=query} . qq{&titles=$page} . qq{&prop=$prop}; return $self->get($url); }
Para testar esse código, precisamos averiguar se o conteúdo da requisição realmente contém os valores esperados:
use Test::More; use Data::Dump; my $expected = { query => { pages => { 39 => { ns => 0, pageid => 39, revisions => [ { anon => "", comment => "", parentid => 69, revid => 4916, timestamp => "2004-06-27T17:34:56Z", user => "81.220.117.157", }, ], title => "Main Page", }, }, }, }; my $wapi = Wikipedia::API->new; is_deeply( $wapi->query( 'Main Page', 'revisions' ), $expected ); done_testing();
Porém o sucesso do teste depende de uma série de fatores externos que não necessariamente envolvem a corretude do código, como ter acesso ao servidor remoto que está sendo testado e depender que o serviço retorne sempre os mesmos valores; no exato momento em que você lê isso, provavelmente o valor retornado pelo código será diferente. Além disso, numa suíte de testes grande executar requisições remotas pode ser demorado e tedioso.
Plack::Test::Agent ao resgate
Para contornar esses problemas, existe o Plack::Test::Agent, que possui a mesma interface do LWP::UserAgent, porém ele simula requisições contra uma aplicação escrita usando Plack.
O problema é resolvido com o middleware de Cache e um Proxy para o serviço original.
my $ua = Plack::Test::Agent->new( app => builder { enable 'Cache', match_url => '/.*', cache_dir => q{/tmp/api-cache}; mount '/' => Plack::App::Proxy->new( remote => 'http://api.discogs.com', backend => 'LWP' )->to_app; } ); my $wapi = Wikipedia::API->new(ua => $ua);
Observe como “enganamos” a biblioteca para que ela passe pelo nosso proxy recém-montado, que irá responder exatamente da mesma forma que o serviço original, exceto que o middleware de cache irá armazenar cada resposta do servidor localmente, para que, num segundo acesso, não seja necessário entrar em contato com o servidor de fato.
Nesse caso, as requisições ficam cacheadas num diretório temporário, mas os arquivos gerados pelo cache podem ser armazenados no repositório, junto com o código. Se houver necessidade de atualizar os dados do serviço, basta remover os arquivos de cache e corrigir os valores esperados pelo código.
***
Artigo de Eden Cardin, publicado no Equinócio 2013 do grupo São Paulo Perl Mongers – http://sao-paulo.pm.org/equinocio/2013/mar/14-testando-apis-com-plack
Texto sob Creative Commons – Atribuição – Partilha nos Mesmos Termos 3.0 Não Adaptada, mais informações em http://creativecommons.org/licenses/by-sa/3.0/