use warnings; no warnings 'redefine'; use strict; use lib '.'; use Count; print One::foo(); { my $count = Count->new; my $bar = $count->mock; print One::foo(); } print One::foo(); #### package One; sub foo { return "foo\n"; } 1; package Count; sub new { return bless {}, shift; } sub unmock { my $self = shift; *One::foo = \&{ $self->{sub} }; } sub mock { my $thing = shift; my $self; if (ref($thing) eq __PACKAGE__){ $self = $thing; } else { $self = bless {}, __PACKAGE__; } $self->{sub} = \&One::foo; *One::foo = sub { $self->{x} = 'x'; return "baz\n"; }; return $self; } sub DESTROY { my $self = shift; print "destroying...\n"; $self->unmock; } 1; #### my $count; *$sub = sub { @{ $self->{called_with} } = @_; $self->{called_count} = ++$called; if ($self->{side_effect}) { if (wantarray){ my @effect = $self->{side_effect}->(@_); return @effect if @effect; } else { my $effect = $self->{side_effect}->(@_); return $effect if defined $effect; } } return undef if ! $self->{return}; return ! wantarray && @{ $self->{return} } == 1 ? $self->{return}[0] : @{ $self->{return} }; };