App-SimpleBackuper

 view release on metacpan or  search on metacpan

local/lib/perl5/Test/Spec/Mocks.pm  view on Meta::CPAN

is normally uncontrollable (like the time of day). Mocks also allow you to
test your code in isolation, a tenet of unit testing.

There are many other reasons why mock objects might come in handy. See the
L<Mock objects|http://en.wikipedia.org/wiki/Mock_object> article at Wikipedia
for lots more examples and more in-depth coverage of the philosophy behind
object mocking.

=head2 Ecosystem

Test::Spec::Mocks is currently only usable from within tests built with
the Test::Spec BDD framework. 

=head2 Terminology

Familiarize yourself with these terms:

=over 4

=item * Stub object

A stub object is an object created specifically to return canned responses for
a specific set of methods. These are created with the L<stub|/stub()> function.

=item * Mock object

Mock objects are similar to stub objects, but are programmed with both
prepared responses and expectations for how they will be called. If the
expectations are not met, they raise an exception to indicate that the test
failed. Mock objects are created with the L<mock|/mock()> function.

=item * Stubbed method

Stubbed methods temporarily replace existing methods on a class or object
instance. This is useful when you only want to override a subset of an object
or class's behavior. For example, you might want to override the C<do> method
of a DBI handle so it doesn't make changes to your database, but still need
the handle to respond as usual to the C<quote> method.  You'll stub
methods using the L<stubs|/"$thing-E<gt>stubs($method_name)"> method.

=item * Mocked method

If you've been reading up to this point, this will be no surprise.  Mocked
methods are just like stubbed methods, but they come with expectations that
will raise an exception if not met. For example, you can mock a C<save> method
on an object to ensure it is called by the code you are testing, while
preventing the data from actually being committed to disk in your test. Use
the L<expects|/"$thing-E<gt>expects($method)"> method to create mock methods.

=item * "stub", "mock"

Depending on context, these can refer to stubbed objects and methods, or
mocked objects and methods, respectively.

=back

=head2 Using stub objects (anonymous stubs)

Sometimes the code you're testing requires that you pass it an object that
conforms to a specific interface. For example, you are testing a console
prompting library, but you don't want to require a real person to stand by,
waiting to type answers into the console. The library requires an object
that returns a string when the C<read_line> method is called.

You could create a class specifically for returning test console input. But
why do that? You can create a stub object in one line:

  describe "An Asker" => sub {
    my $asker = Asker->new;

    it "returns true when a yes_or_no question is answered 'yes'" => sub {
      my $console_stub = stub(read_line => "yes");
      # $console_stub->read_line returns "yes"
      ok( $asker->yes_or_no($console_stub, "Am I awesome?") );
    };

    it "returns false when a yes_or_no question is answered 'no'" => sub {
      my $console_stub = stub(read_line => "no");
      ok( ! $asker->yes_or_no($console_stub, "Am I second best?") );
    };
  };

Stubs can also take subroutine references.  This is useful when the behavior
you need to mimic is a little more complex.

  it "keeps asking until it gets an answer" => sub {
    my @answers = (undef, "yes");
    my $console_stub = stub(read_line => sub { shift @answers });
    # when console_stub is called the first time, it returns undef
    # the second time returns "yes"
    ok( $asker->yes_or_no($console_stub, "Do I smell nice?") );
  };

=head2 Using mock objects

If you want to take your tests one step further, you can use mock objects
instead of stub objects. Mocks ensure the methods you expect to be called
actually are called. If they aren't, the mock will raise an exception which
causes your test to fail.

In this example, we are testing that C<read_line> is called once and only
once (the default for mocks).

  it "returns true when a yes_or_no question is answered 'yes'" => sub {
    my $console_mock = mock();
    $console_mock->expects('read_line')
                 ->returns("yes");
    # $console_mock->read_line returns "yes"
    ok( $asker->yes_or_no($console_mock, "Am I awesome?") );
  };

If Asker's C<yes_or_no> method doesn't call C<read_line> on our mock exactly
one time, the test would fail with a message like:

  expected read_line to be called exactly 1 time, but it was called 0 times

You can specify how many times your mock should be called with "exactly":

  it "keeps asking until it gets an answer" => sub {
    my @answers = (undef, "yes");
    my $console_mock = mock();



( run in 1.368 second using v1.01-cache-2.11-cpan-6aa56a78535 )