How to handle mocking roles in Moose?

梦想与她 提交于 2019-12-04 11:34:14

My first suggestion would be something like MooseX::Traits and then specify the different roles at object creation:

my $test = A->with_traits('Simple::Tax')->new(...);

my $prod = A->with_traits('Complex::Tax')->new(...);

But this opens the door to an A being created without either Role being applied. So thinking about it further, I think you've got an X/Y problem. If Simple::Tax is only ever used to mock up Complex::Tax in a test environment you can do several things to override the Complex::Tax implementation.

For example you could just define Simple::Tax like so:

package Simple::Tax; 
use Moose::Role;

requires 'calculate_tax';
around calculate_tax => sub { int($_[1]->price * 0.05) };

Then always have A compose Complex::Tax and apply Simple::Tax to it only during tests (using apply_all_roles).

If however you need Simple::Tax and Complex::Tax both in production (and not simply for testing) your best bet is refactor from a composition relationship (does) to a delegation relationship (has).

 package TaxCalculator::API;
 use Moose::Role;

 requires qw(calculate_tax);

 package SimpleTax::Calculator;
 use Moose;
 with qw(TaxCalculator::API);

 sub calculate_tax { ... }

 package ComplexTax::Calculator;
 use Moose;
 with qw(TaxCalculator::API);

 sub calcuate_tax { ... }


 package A;
 use Moose;

 has tax_calculator => ( 
      does => 'TaxCalculator::API', 
      handles => 'TaxCalculator::API', 
      default => sub { ComplexTax::Calculator->new() },
 );

Then if you want to override it you simply pass in a new tax_calculator:

my $test = A->new(tax_calculator => SimpleTax::Calculator->new());

my $prod = A->new(tax_calculator => ComplexTax::Calculator->new());

Because handles will delegate all of the methods from the role as new proxies this is practically identical to having composed the role yourself.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!