Introducing Magpie – flexible test doubles & mocking for Perl
November 19, 2010 § 3 Comments
Introduction
Magpie is a new distribution I have just released which brings the power of test doubles to Perl. There are already a few solutions to test doubles in Perl, but Magpie takes a different approach. Inspired heavily by Mockito for Java, Magpie gives you test doubles that are based are spying and verification, not expectations. So, before we really dive into it, how does it look?
use Test::Magpie qw( mock when ); use Test::More; my $mocked_list = mock; when($mocked_list)->get(0)->then_return('first'); when($mocked_list)->get(1)->then_die('Kaboom!'); is($mocked_list->get(0) => 'first'); ok(exception { $mocked_list->get(1) }); is($mocked_list->get => undef);
So, what’s going on here? First of all we create a mock
object. This object does every role, is a subclass of every class, and can run any method (returning undef
by default). We then stub this object to handle some method calls using the when
construct. We specify that when we request item 0 from our mocked list we should return the string ‘first’ and when request item 1, we throw an exception string ‘Kaboom!’. Simple! And as you can see, the tests following all verify this behaviour – this example is straight out of t/mockito_examples.t
What does Magpie have to offer?
What you just saw was the basics of Magpie – there are a lot more cool features available, that come in to be very useful!
Verification
As well as stubbing methods, you can also verify that methods were called. The following example from the synopsis illustrates how this may be useful:
use Test::Magpie qw( mock verify when ); my $baker = mock; my $bakery = Bakery->new( bakers => [ $baker ] ); my $bread = $bakery->buy_loaf( amount => 2, type => 'white' ); verify($baker, times => 2)->bake_loaf('white');
As you can see, we are able to verify a method was called, and also add some extra details – for now the amount of times a method was called, and which arguments it was called with.
Argument matchers
Argument matchers allow you to be more general in your specification for stubs and verification. Rather than saying “when this method is called with exactly these arguments” we can say the more general “when this method is called with arguments that match these predicates.” In practice, it might look like this:
when($child)->eat(type(Broccoli))->then_die('Yuck!'); when($child)->eat(type(SugaryGoodness))->then_return('Ooo, yum!')
In this example Broccoli
and SugaryGoodness
are type constraints. There are already a few argument matchers that ship with Magpie, and it’s trivial to define your own with the custom_matcher
generator.
Extra extra! Read more about it!
There’s more to Test::Magpie than what I’ve mentioned in this post, but if you’re interested, I recommend the official documentation. The basic and Mockito example tests serve as a great demonstration of how Magpie can be practically used.
Go go gadget CPAN – installing Magpie
Magpie is already available for use now, and is on cpan:
cpan Test::Magpie
From your shell, or however you wish to install CPAN modules
I really hope you enjoy this module, I’m already finding it powerful enough to use at work
. If you have any criticisms, bugs, feature requests, or ponys to give me – drop me a comment here, an issue on RT, or poke me on IRC (I’m ocharles).
Happy testing!
Edit: 0.04 had a release problem and might not have installed cleanly. 0.05 should fix this. Sorry!
So this is a mocking framework?
Yep, that’s right – but takes a slightly different approach from what I saw of other frameworks
I just started using this and I like it a lot. With other mocking frameworks I used, it took a long time to write the expected behaviour. But this enabled me to get the tests up and running really quick!