Consider this approach:
In your Moose class define an 'abstract' method called make_request
. Then define two roles which implement make_request
- one which calls Foo::Request->new
and another one which calls Test::MockObject->new
.
Example:
Your main class and the two roles:
package MainMooseClass;
use Moose;
...
# Note: this class requires a role that
# provides an implementation of 'make_request'
package MakeRequestWithFoo;
use Moose::Role;
use Foo::Request; # or require it
sub make_request { Foo::Request->new(...) }
package MakeRequestWithMock;
use Moose::Role;
use Test::MockRequest; # or require it
sub make_request { Test::MockRequest->new(...) }
If you want to test your main class, mix it with the 'MakeRequestWithMock' role:
package TestVersionOfMainMooseClass;
use Moose;
extends 'MainMooseClass';
with 'MakeRequestWithMock';
package main;
my $test_object = TestVersionOfMainMooseClass->new(...);
If you want to use it with the Foo implementation of 'make_request', mix it in with the 'MakeRequestWithFoo' role.
Some advantages:
You will only load in modules that you need. For instance, the class TestVersionOfMainMooseClass
will not load the module Foo::Request
.
You can add data that is relevant/required by your implementation of make_request
as instance members of your new class. For example, your original approach of using a CODEREF can be implemented with this role:
package MakeRequestWithCodeRef;
use Moose::Role;
has request_builder => (
is => 'rw',
isa => 'CodeRef',
required => 1,
);
sub make_request { my $self = shift; $self->request_builder->(@_) };
To use this class you need to supply an initializer for request_builder
, e.g.:
package Example;
use Moose;
extends 'MainMooseClass';
with 'MakeRequestWithCodeRef';
package main;
my $object = Example->new(request_builder => sub { ... });
As a final consideration, the roles you write might be usable with other classes.