Reputation: 8571
I try to mock a function in Net::Twitter:
use strict;
use warnings;
use Test::MockModule;
my $mock = Test::MockModule->new('Net::Twitter');
$mock->redefine('update', sub {
# ...
});
but when I run this, I get:
Net::Twitter::update does not exist! at wtf.pl line 8.
Why is that and how can I actually mock the Net::Twitter::update
function?
Upvotes: 2
Views: 377
Reputation: 54323
The error message means that it can't find Net::Twitter::update
to overwrite. That's pretty clear. The question is, why?.
If you take a look at a Net::Twitter object with Data::Printer, you'll see that there is indeed no update
method apparent. In fact, it's not even an object of the type Net::Twitter
.
use Net::Twitter;
use Data::Printer;
my $t = Net::Twitter->new;
p $t;
On my machine with the currently newest Net::Twitter installed, it's a Net::Twitter_v4_01042_with__Legacy
, which is likely a dynamically created package.
Net::Twitter_v4_01042_with__Legacy {
Parents Net::Twitter::Core
public methods (22) : apihost, apirealm, apiurl, arrayref_on_error, BUILD, DESTROY, has_error, http_code, http_message, is_list_member, is_list_subscriber, is_subscribed_list, meta, new, searchapiurl, trends, tvhost, tvrealm, tvurl, twittervision, update_twittervision, upload_url
private methods (5) : _clear_error, _error_return_val, _http_response, _parse_result, _twitter_error
internals: {
apirealm "Twitter API",
apiurl "https://api.twitter.com/1",
arrayref_on_error 0,
clientname "Perl Net::Twitter",
clienturl "http://search.cpan.org/dist/Net-Twitter/",
clientver 4.01042,
decode_html_entities 0,
_error_return_val undef,
_json_handler Cpanel::JSON::XS,
<<MOP>> Class::MOP::Class::Immutable::Moose::Meta::Class,
netrc_machine "api.twitter.com",
searchapiurl "https://search.twitter.com",
source "twitterpm",
ssl 1,
tvhost "twittervision.com:80",
tvrealm "Web Password",
tvurl "http://twittervision.com",
twittervision 0,
upload_url "https://upload.twitter.com/1",
useragent "Net::Twitter/4.01042 (Perl)",
useragent_args {},
useragent_class "LWP::UserAgent"
}
}
If you try looking for a sub update
in the entire Net::Twitter distribution, you'll find nothing. It's not part of a role, it just doesn't exist.
But that does not mean it's not there. I dug a little deeper, and found an update
in Net::Twitter::Role::API::REST. It's defined using the twitter_api_method
function from Net::Twitter::API. It does a bunch of things and then uses Moose's meta layer to install the method into some class – probably Net::Twitter_v4_01042_with__Legacy
on my machine` – and even brings its own meta method class Net::Twitter::Meta::Method.
So it's fairly obvious why Test::MockModule wouldn't find Net::Twitter::update
. It simply never
But how do we mock it for testing?
I believe the simplest approach, though certainly not a very nice one, is to overwrite update
in the package that it exists in. For that, you need to create an object and check.
use strict;
use warnings;
use Test::MockModule;
use Net::Twitter;
my $mock = Test::MockModule->new( ref( Net::Twitter->new ) );
$mock->redefine(
'update',
sub {
... # will die with 'unimplemented'
}
);
my $nt = Net::Twitter->new->update;
This code is a little wasteful, because it needs to create an object just to check what package it ended up in, but it works.
Unimplemented at /home/simbabque/code/scratch/scratch.pl line 236.
Upvotes: 5