SilasTheMonk has asked for the wisdom of the Perl Monks concerning the following question:

I have been struggling with the Test::MockObject documentation for some time. However I think I finally got it today. The thing is that just about every class I ever wish to mock is some sort of file handle. I suppose it is too much to ask to expect the natural "print" syntax to work when mocked up, but it does limit the usefulness of the testing. I have an example:
#!perl use strict; use warnings; use FileHandle; use Test::MockObject::Extends; my $mock= Test::MockObject::Extends->new(FileHandle->new); $mock->set_false( 'print' ); $mock->fake_new('FileHandle'); my $a = FileHandle->new; $a->open(">K") or die "could not open"; print {$a} "hello" or die "I expect to die here"; $a->print("hello") or die "I expect to be dead before we get to this p +oint";
When it runs on my system the output is "I expect to be dead before we get to this point at print.t line 15." and the file "K" says "hello".

Edit:I have put together a more basic example.

#!perl use strict; use warnings; package A; sub new { my $class = shift; return bless {}, $class; } sub whoami { my $self = shift; return "I am an A.\n"; } sub sayhi { my $self = shift; return "Hi!\n"; } package main; my $a = A->new; print $a->whoami; print $a->sayhi; use Test::MockObject::Extends; $a = Test::MockObject::Extends->new($a); $a->mock('sayhi', sub {return "Nope. Won't say 'Hi!'.\n";}); my $a2 = A->new; print $a2->whoami; print $a2->sayhi; $a->fake_new('A'); my $a3 = A->new; print $a3->whoami; print $a3->sayhi;

Replies are listed 'Best First'.
Re: Test::MockObject::Extends and FileHandle
by chromatic (Archbishop) on Jan 23, 2010 at 01:58 UTC

    You're missing a couple of things. First, you have to use the T::MO::E instance ($mock) rather than fake_new() here. fake_new() is for when you don't want to use the other class at all, which is not what you're doing.

    Otherwise, the method form is really the best way I know of to make this code work. Perl 5's too clever in figuring out the indirect invocation syntax here.

      First, you have to use the T::MO::E instance ($mock) rather than fake_new() here. fake_new() is for when you don't want to use the other class at all, which is not what you're doing.
      chromatic, I am sorry this leaves me no wiser. What code exactly am I supposed to use instead of the fake_new line. If I comment out the fake_new line I can see that there is no faking at all. What advance did Wiley offer you for "Test::MockObject for dummies"? I think the book is needed.
        If I comment out the fake_new line I can see that there is no faking at all.

        Sure there is; pass an object to the T::MO::E constructor. The object you get back is your mock object. Any methods you add to that object are mock objects for that specific method. Thus you need to use that object (the T::MO::E instance), not a new object.

        I tried this. Look in the home directory afterwards for "K":
        #!/usr/bin/perl use strict; use warnings; use FileHandle; use File::Tee qw(tee); use Test::MockObject::Extends; tee('STDOUT', '>>', 'stdout.txt'); my $mock= Test::MockObject::Extends->new(FileHandle->new); $mock->set_false( 'print' ); $mock->mock('FileHandle'); my $a = FileHandle->new; die "could not open" unless $a->open('>K'); die "I expect to die here" unless print {$a;} "hello"; die "I expect to be dead before we get to this point" unless $a->print("hello"); print $a;
Re: Test::MockObject::Extends and FileHandle
by Khen1950fx (Canon) on Jan 23, 2010 at 01:42 UTC