Abhinay
Abhinay

Reputation: 31

Mock a Perl module having multiple packages

I have the following scenario where I need to mock the subroutines in a module which has multiple packages.

My Module(moddemo.pm)

package A;

sub helloa
{
  print "Hello, Im in demomod module of package A\n";
  return 1;
}

package B;

sub hellob
{
 print "Hello, Im in demomod module of package B\n";
 return 1;
}

1;

I need to mock A::helloa(), B::hellob() subroutines. Here is the code I have tried, but failed.

#!/usr/bin/perl
use Test::MockModule;
use moddemo;

{
 my $mockobj = new Test::MockModule('moddemo');
 $mockobj->mock('A::helloa', sub { print "This is mocked object calling helloa function\n"; });
 $mockobj->mock('B::hellob', sub { print "This is mocked object calling hellob function\n";});
 modobj::A::helloa();
 modobj::B::hellob();
}

Any help how to mock these subroutines? Thanks in advance.

Upvotes: 2

Views: 783

Answers (2)

stevenl
stevenl

Reputation: 6798

I've done it by redefining the subroutine.

use strict;
use warnings;
use Demo;

A::helloa();
{
    no warnings 'redefine';
    local *A::helloa = sub {
        print "helloa has changed\n";
        return 1;
    };
    A::helloa();
}
A::helloa();

Notes:

  • The redefinition will cause a warning, so the no warnings line is needed to get rid of that.
  • The redefinition is applied locally, so you should see that only the subroutine call within the block has changed.

Upvotes: 1

afenster
afenster

Reputation: 3608

I can be wrong but from what I see in the module source it seems impossible to use it in the way you try. MockModule first requires the needed package (.pm file) and then allows only subroutines from that package, i.e. no :: in names are allowed.

As I understand it can be used in this way for testing modules (modified your code to fit its expectations):

moddemo.pm:

package moddemo;
use strict;
use warnings;

sub helloa
{
        print "moddemo::helloa\n";
        return 1;
}

sub hellob
{
        print "moddemo::hellob\n";
        return 1;
}

1;

Now the test file, test.pl:

use strict;
use warnings;

use Test::MockModule;
use moddemo;

{
        my $mockobj = new Test::MockModule('moddemo');
        $mockobj->mock('helloa', sub { print "This is mocked object calling helloa function\n"; });
        $mockobj->mock('hellob', sub { print "This is mocked object calling hellob function\n";});

        # mocked versions
        moddemo::helloa();
        moddemo::hellob();
}

# now original versions
moddemo::helloa();
moddemo::hellob();

And finally the output, as expected:

This is mocked object calling helloa function
This is mocked object calling hellob function
moddemo::helloa
moddemo::hellob

Upvotes: 0

Related Questions