1 package Test::MockObject::Extends;
8 use Devel::Peek 'CvGV';
9 use Scalar::Util 'blessed';
11 use vars qw( $VERSION $AUTOLOAD );
16 my ($class, $fake_class) = @_;
18 return Test::MockObject->new() unless defined $fake_class;
20 my $parent_class = $class->get_class( $fake_class );
21 $class->check_class_loaded( $parent_class );
22 my $self = blessed( $fake_class ) ? $fake_class : {};
24 bless $self, $class->gen_package( $parent_class );
27 sub check_class_loaded
29 my ($self, $parent_class) = @_;
30 my $result = Test::MockObject->check_class_loaded(
33 return $result if $result;
35 (my $load_class = $parent_class) =~ s/::/\//g;
36 require $load_class . '.pm';
41 my ($self, $invocant) = @_;
43 return $invocant unless blessed $invocant;
51 my ($class, $parent) = @_;
52 my $package = 'T::MO::E::' . $packname++;
55 *{ $package . '::mock' } = \&mock;
56 *{ $package . '::unmock' } = \&unmock;
57 @{ $package . '::ISA' } = ( $parent );
58 *{ $package . '::can' } = $class->gen_can( $parent );
59 *{ $package . '::isa' } = $class->gen_isa( $parent );
60 *{ $package . '::AUTOLOAD' } = $class->gen_autoload( $parent );
61 *{ $package . '::__get_parents' } = $class->gen_get_parents( $parent );
68 my ($self, $parent) = @_;
72 return @{ $parent . '::ISA' };
78 my ($class, $parent) = @_;
82 local *__ANON__ = 'isa';
83 my ($self, $class) = @_;
84 return 1 if $class eq $parent;
85 my $isa = $parent->can( 'isa' );
86 return $isa->( $self, $class );
92 my ($class, $parent) = @_;
96 local *__ANON__ = 'can';
97 my ($self, $method) = @_;
98 my $parent_method = $self->SUPER::can( $method );
99 return $parent_method if $parent_method;
100 return Test::MockObject->can( $method );
106 my ($class, $parent) = @_;
110 my $method = substr( $AUTOLOAD, rindex( $AUTOLOAD, ':' ) +1 );
111 return if $method eq 'DESTROY';
115 if (my $parent_method = $parent->can( $method ))
117 return $self->$parent_method( @_ );
119 elsif (my $mock_method = Test::MockObject->can( $method ))
121 return $self->$mock_method( @_ );
123 elsif (my $parent_al = $parent->can( 'AUTOLOAD' ))
125 my ($parent_pack) = CvGV( $parent_al ) =~ /\*(.*)::AUTOLOAD/;
128 ${ "${parent_pack}::AUTOLOAD" } = "${parent}::${method}";
135 die "Undefined method $method at ", join( ' ', caller() ), "\n";
142 my ($self, $name, $sub) = @_;
144 Test::MockObject::_set_log( $self, $name, ( $name =~ s/^-// ? 0 : 1 ) );
149 $self->log_call( $name, @_ );
155 no warnings 'redefine';
156 *{ ref( $self ) . '::' . $name } = $mock_sub;
164 my ($self, $name) = @_;
166 Test::MockObject::_set_log( $self, $name, 0 );
168 my $glob = *{ ref( $self ) . '::' };
169 delete $glob->{ $name };
178 Test::MockObject::Extends - mock part of an object or class
183 use Test::MockObject::Extends;
185 # create an object to mock
186 my $object = Some::Class->new();
188 # wrap that same object with a mocking wrapper
189 $object = Test::MockObject::Extends->new( $object );
191 # now chain mock and control calls
192 $object->set_true( 'parent_method' )
193 ->set_always( -grandparent_method => 1 )
198 Test::MockObject::Extends lets you mock one or more methods of an existing
199 object or class. This can be very handy when you're testing a well-factored
200 module that does almost exactly what you want. Wouldn't it be handy to take
201 control of a method or two to make sure you receive testable results? Now you
208 =item C<new( $object | $class )>
210 C<new()> takes one optional argument, the object or class to mock. If you're
211 mocking a method for an object that holds internal state, create an appropriate
212 object, then pass it to this constructor. B<NOTE:> this will modify the object
215 If you're mocking an object that does not need state, as in the cases where
216 there's no internal data or you'll only be calling class methods, or where
217 you'll be mocking all of the access to internal data, you can pass in the name
218 of the class to mock partially.
220 If you've not yet loaded the class, this method will try to load it for you.
221 This may fail, so beware.
223 If you pass no arguments, it will assume you really meant to create a normal
224 C<Test::MockObject> object and will oblige you.
226 Note that if you pass a class, the object returned will appear to be an
227 instance of that class; I<this does not mock the class itself>.
229 =item C<mock( $methodname, $sub_ref )>
231 See the documentation for Test::MockObject for all of the ways to mock methods
232 and to retrieve method logging information. These methods return the invocant,
233 so you can chain them.
235 =item C<unmock( $methodname )>
237 Removes any active mocking of the named method. This means any calls to that
238 method will hit the method of that name in the class being mocked, if it
239 exists. This method returns the invocant, you can chain it.
241 =item C<isa( $class )>
243 As you'd expect from a mocked object, this will return true for the class it's
248 =head1 INTERNAL METHODS
250 To do its magic, this module uses several internal methods:
254 =item * C<check_class_loaded( $parent_class )>
256 This verifies that you have the mockee defined. If not, it attempts to load
257 the corresponding module for you.
259 =item * C<gen_autoload( $extended )>
261 Returns an AUTOLOAD subroutine for the mock object that checks that the
262 extended object (or class) can perform the requested method, that
263 L<Test::MockObject> can perform it, or that the parent has an appropriate
264 AUTOLOAD of its own. (It should have its own C<can()> in that case too
267 =item * C<gen_can( $extended )>
269 Returns a C<can()> method for the mock object that respects the same execution
270 order as C<gen_autoload()>.
272 =item * C<gen_isa( $extended )>
274 Returns an C<isa()> method for the mock object that claims to be the
275 C<$extended> object appropriately.
277 =item * C<gen_get_parents( $extended )>
279 Returns a C<__get_parents()> method for the mock object that claims to be the
280 C<$extended> object appropriately.
282 =item * C<gen_package( $extended )>
284 Creates a new unique package for the mock object with the appropriate methods
287 =item * C<get_class( $invocant )>
289 Returns the class name of the invocant, whether it's an object or a class name.
295 There may be some weird corner cases with dynamically generated methods in the
296 mocked class. You really should use subroutine declarations though, or at
297 least set C<can()> appropriately.
299 There are also potential name collisions with methods in this module or
300 C<Test::MockObject>, though this should be rare.
304 chromatic, E<lt>chromatic at wgz dot orgE<gt>
306 Documentation bug fixed by Stevan Little. Additional AUTOLOAD approach
307 suggested by Adam Kennedy. Other bugs reported by Paul the Nomad and Praveen
316 Copyright (c) 2004 - 2008, chromatic. All rights reserved. You may use,
317 modify, and distribute this module under the same terms as Perl 5.10