Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??


Unit testing on object aggregations are usually hard to develop because you may need to instantiate several complex objects, so you may wind up doing integral testing in order to test some very specific subclass. Test::MockObject, written by chromatic was designed to aid with this situation, nevertheless some things may not be immediately apparent for the novice user. Also, if you are testing OO stuff that uses accessors (Class::Accessor, Moose, etc.) you may find it difficult to do so. This tutorial is targeted for example to Moose developers, who will frequently encounter accessors and isa validations (see Moose::Manual::Attributes).


Unit testing does not excuse you from doing integral testing with the real objects. Just as the author of Test::MockObject warned me before writing this tutorial: "if you have to mock an accessor, you're probably mocking too much" Re: RFC Mocking an Accessor with Test::MockObject. So, you have been warned. Please revise the pod for Test::MockObject and Test::MockObject::Extends before using the techniques explained here.


Test::MockObject allows you to create objects that mock certain specific functionality, and that don't depend on anything more than the Test::MockObject module. It also allows for you to cheat Perl into thinking that a package has already been loaded, preventing Perl from doing so in your test, and forcing it to use your mocked package instead. More so, you can also fiddle with the mocked object's isa so that your mocked objects may pass UNIVERSAL->isa validations in the target code. What Test::MockObject does not currently do, is provide a simple mechanism to emulate accessors.

Here is one method to do it, maybe not the best, but will do the job. The example is mocking an object that uses another object which is also mocked, showing off some of the the powers of Test::MockObject.

use warnings; use strict; use Test::More; use Test::MockObject; # should be declared before the BEGIN block (see perlmod) my ($mocked_foo, $mocked_bar); # fake_module is in BEGIN to prevent loading of the actual package BEGIN { # create the mocked objects $mocked_foo = Test::MockObject->new(); $mocked_bar = Test::MockObject->new(); # prevent Perl from loading the mocked class $mocked_foo->fake_module('Class::To::Mock::Foo'); $mocked_bar->fake_module('Class::To::Mock::Bar'); # cheat the target code $mocked_foo->set_isa('Class::To::Mock::Foo'); $mocked_bar->set_isa('Class::To::Mock::Bar'); # load the class to test use_ok 'Your::Test::Class'; } # set up the mockery for foo # this scalar will hold the value of the get/get operations # of the fake accessors my $accessor_one_scalar = 'init_value'; $mocked_foo->mock( 'accessor_one', sub {shift; &mock_accessor_scalar(\$accessor_one_scalar,@_)} ); # now mock foo in bar $mocked_bar->mock('foo', sub { return $mocked_foo }); # use the mocked object in your target code my $test_target = Your::Test::Class->new( bar => $mocked_bar, ); # ================== # Actual Tests Here # ================== # use the scalars in your tests for example # suppose your target code does something like: # $self->bar->foo->accessor_one('test_value'); ok($test_target->mess_with_bar_foo, 'Operation on mocked bar that affects foo'); cmp_ok($accessor_one_scalar, 'eq', 'test value', 'Result of operation in foo'); # end of tests done_testing(); # emulates a simple accessor to a scalar sub mock_accessor_scalar { my $var = shift; if(@_){ $$var = shift; } else{ return $$var; } }

In reply to Mocking accessors with Test::MockObject by ait

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?

    What's my password?
    Create A New User
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others exploiting the Monastery: (2)
    As of 2020-09-26 01:48 GMT
    Find Nodes?
      Voting Booth?
      If at first I donít succeed, I Ö

      Results (141 votes). Check out past polls.