I've got a sub that retrieves some data from an API via a REST service. The code is rather simple, but I need to post parameters to the API and I need to use SSL, so I have to go through LWP::UserAgent and cannot use LWP::Simple. This is a simplified version of it.
sub _request {
my ( $action, $params ) = @_;
# User Agent fuer Requests
my $ua = LWP::UserAgent->new;
$ua->ssl_opts( SSL_version => 'SSLv3' );
my $res = $ua->post(
$url{$params->{'_live'} ? 'live' : 'test'}, { action => $action, %$params }
);
if ( $res->is_success ) {
my $json = JSON->new;
return $json->decode( $res->decoded_content );
} else {
cluck $res->status_line;
return;
}
}
This is the only place in my module (which is not OOp) where I need the $ua
.
Now I want to write a test for this and after some research decided it would be best to use Test::LWP::UserAgent, which sounds really promissing. Unfortunately, there's a catch. In the doc, it says:
Note that LWP::UserAgent itself is not monkey-patched - you must use this module (or a subclass) to send your request, or it cannot be caught and processed.
One common mechanism to swap out the useragent implementation is via a lazily-built Moose attribute; if no override is provided at construction time, default to LWP::UserAgent->new(%options).
Arghs. Obviously I cannot do the Moose thing. I can't just pass a $ua
to the sub, either. I could of course add an optional third param $ua
to the sub, but I don't like the idea of doing that. I feel it's not ok to alter the behaviour of such simple code so radically just to make it testable.
What I basically want to do is run my test like this:
use strict;
use warnings;
use Test::LWP::UserAgent;
use Test::More;
require Foo;
Test::LWP::UserAgent->map_response( 'www.example.com',
HTTP::Response->new( 200, 'OK',
[ 'Content-Type' => 'text/plain' ],
'[ "Hello World" ]' ) );
is_deeply(
Foo::_request('https://www.example.com', { foo => 'bar' }),
[ 'Hello World' ],
'Test foo'
);
Is there a way to monkeypatch the Test::LWP::UserAgent functionality into LWP::UserAgent so that my code just uses the Test:: one?