If you're enforcing the object type you have to draft in Test::MockObject, which is great, but is also substantially more complex.
You can still use the self-shunt unit testing pattern with enforced object types and Test::Class if you take advantage of perl's run-time method dispatch.
For example, consider a class that takes an optional logging object to allow custom logging on an object by object basis.
package Object; use Params::Validate qw(:all); sub new { my $class = shift; my %self = validate(@_, {logger => { isa => 'Logger' } } ); return( bless \%self, $class ); }; # ... more code ... sub log { my ($self, @messages) = @_; $self->{logger}->log($self, @messages); };
One way to test Object's log method would be to create a mock Logger object with Test::MockObject and pass this to Object->new. Instead, we will make the Test::Class pretend to be a Logger object.
package Object::Test; use base qw(Test::Class); use Test::More; # run $code while pretending that __PACKAGE__ ISA $class sub _do_as(&$) { my ($code, $class) = @_; { # we have to make sure the package hash exists # for the method dispatch to work no strict 'refs'; *{"$class\::"}{HASH} }; local @Object::Test::ISA = ($class, @Object::Test::ISA); $code->(); }; sub setup : Test(setup) { my $self = shift; _do_as { $self->{object} = Object->new(logger => $self) } 'Logger' +; }; sub test_show_answer : Test(3) { my $self = shift; _do_as { $self->{object}->log("hello", "there") } 'Logger'; }; sub log { my $self = shift; is($_[0], $self->{object}, 'passed object to logger'); is($_[1], "hello", 'passed arg1'); is($_[2], "there", 'passed arg2'); };
Sneaky - eh?
In reply to Test::Class & self-shunt pattern
by adrianh
in thread Documenting Methods/Subs
by vek
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |