Test::Shadow - override a class's methods in a scope, checking input/output
Provides RSpec-like mocking with 'receive'/'and_return' functionality. However the interface is more explicit. This may be considered a feature.
use Test::More; use Test::Shadow; use Foo; with_shadow Foo => inner_method => { in => [ 'list', 'of', 'parameters' ], out => 'barry', count => 3 }, sub { my $foo = Foo->new; $foo->outer_method(); };
Exported by default
with_shadow $class1 => $method1 => $args1, ..., $callback;
Each supplied class/method is overridden as per the specification in the supplied args. Finally, the callback is run with that specification.
The args passed are as follows:
A list of parameters to compare every call of the method against. This will be checked each time, until the first failure, if any. The parameters can be supplied as an arrayref:
in => [ 'list', 'of', 'parameters' ]
or a hashref:
in => { key => 'value', key2 => 'value2 },
and the comparison may be made using any of the extended routines in Test::Deep
use Test::Deep; with_shadow Foo => inner_method => { in => { foo => any(1,2,3) }, ...
Stub the return value. This can be
a simple (non-reference) scalar value
... out => 100,
a subroutine ref, which will be passed at every invocation the parameters ($orig, $self, @args).
($orig, $self, @args)
Note that the subroutine args are the same as if you were creating a Moose or Class::Method::Modifiers around wrapper, but dynamically scoped to the test.
around
out => sub { my ($orig, $self, @args) = @_; ... },
If you want to return a reference (including a subroutine reference) return this from the subroutine: We require wrapping in a subroutine ref for the same reason that Moose's default does: otherwise we would end up passing the same reference to each invocation, with possibly surprising results.
default
out => sub { [] }, # return a new, empty arrayref on each invocation
Of course you can simply ignore the call args and invoke as a subroutine. See also the "iterate" function.
The number of times you expect the method to be called. This is checked at the end of the callback scope.
This may be an exact value:
count => 4,
Or a hashref with one or both of min and max declared:
min
max
count => { min => 5, max => 10 },
We provide a helper function to iterate over a number of scalar return values. This can be attached to out, and takes a list of values to be provided as the stubbed return value on each successive call.
out
use Test::Shadow 'iterate'; with_shadow ... out => iterate(1,2,3,4), # return 1 on first invocation, 2 on second, etc. ...
The values wrap if they run out: you may want to use a count argument to diagnose that this has happened.
count
As well as simple values, iterate handles method calls in exactly the same format as they are normally passed to out.
iterate
with_shadow ... out => iterate( sub { my ($orig, $self, $arg) = @_; ... }, ...
There are several other modules that deal with mocking objects. One of them may well serve your needs better. I was having RSpec envy, about the call expectation side of things (not about the "English-like" DSL, which I found both confusing, and slightly filthy) so Test::Shadow is designed to cover that use case with an API that is less magical and more Perlish (thanks to ribasushi, haarg, tobyink, vincent, ether on #perl-qa for pointing out that my first implementation with the lovely-but-frightening Scope::Upper may not have been the poster child for sanity I'd intended.)
Test::MockObject is the oldest CPAN library I'm aware of. It has a very different usage, where you create an object instance and stub methods on it, rather than mocking a class.
Test::MockModule does mock a class's methods, but hasn't been updated since 2005, and doesn't give the control over return value stubbing and call count tracing.
Mock::Quick looks like a more modern mocking implementation. Again, it looks like this works on an object instance.
Test::Spec looks like a good reimplementation of RSpec, which means that personally I dislike aspects of the API -- the monkey-patching and the confusing expects and returns keywords, but this may be a good choice. Note that the ::Mocks routines are "currently only usable from within tests built with the Test::Spec BDD* framework".
expects
returns
* my current (snarky) understanding is that "BDD" means something to do with using it and describe as synonyms for subtest.
it
describe
subtest
Copyright 2014 Hakim Cassimally <osfameron@cpan.org>
This module is released under the same terms as Perl.
To install Test::Shadow, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Test::Shadow
CPAN shell
perl -MCPAN -e shell install Test::Shadow
For more information on module installation, please visit the detailed CPAN module installation guide.