I'm writing a new module called Test::MockObject. It has a test that reads:
$mock->add('foo'); can_ok( $mock, 'foo' ); Test::MockObject has a custom can() method, which checks instance data to decide if the object can handle the method: sub can { my ($self, $sub) = @_; return exists $self->{_subs}{$sub}; } Attached is a patch to make Test::More do the right thing (as I see it) in this case. Previously, it called can() on the class name, which obviously doesn't work here. I suspect something similar should be done for isa_ok(). The included test fails with vanilla 0.43 and passes with the attached patch. Maybe it would be better to bless a scalar, -- c --- lib/Test/More.old Sat Apr 20 11:29:07 2002 +++ lib/Test/More.pm Sat Apr 20 11:44:56 2002 @@ -454,21 +454,21 @@ =cut sub can_ok ($@) { - my($proto, @methods) = @_; - my $class= ref $proto || $proto; + my($class, @methods) = @_; unless( @methods ) { my $ok = $Test->ok( 0, "$class->can(...)" ); $Test->diag(' can_ok() called with no methods'); return $ok; } + my $can_test = ref( $class ) ? + sub { $class->can($_[0]) } : sub { eval "$class->can('$_[0]')" }; my @nok = (); foreach my $method (@methods) { - my $test = "'$class'->can('$method')"; local($!, $@); # don't interfere with caller's $@ # eval sometimes resets $! - eval $test || push @nok, $method; + eval { $can_test->($method) } || push @nok, $method; } my $name; --- t/More.old Sat Apr 20 11:29:25 2002 +++ t/More.t Sat Apr 20 11:44:58 2002 @@ -7,7 +7,7 @@ } } -use Test::More tests => 37; +use Test::More tests => 39; # Make sure we don't mess with $@ or $!. Test at bottom. my $Err = "this should not be touched"; @@ -38,10 +38,19 @@ can_ok(bless({}, "Test::More"), qw(require_ok use_ok ok is isnt like skip can_ok pass fail eq_array eq_hash eq_set)); +# can_ok() should call can() on object, not just class, in case of custom can() +{ + local *Foo::can; + *Foo::can = sub { $_[0]->[0] }; + my $foo = bless([0], 'Foo'); + ok( ! $foo->can('bar') ); + $foo->[0] = 1; + can_ok( $foo, 'blah'); +} + isa_ok(bless([], "Foo"), "Foo"); isa_ok([], 'ARRAY'); isa_ok(\42, 'SCALAR'); - pass('pass() passed');