The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Test::Mockify::Sut - injection options for your System under test (Sut) based on Mockify

SYNOPSIS

  use Test::Mockify::Sut;
  use Test::Mockify::Verify qw ( WasCalled );
  use Test::Mockify::Matcher qw ( String );

  # build a new system under text
  my $MockifySut = Test::Mockify::Sut->new('Package::I::Like::To::Test', []);
  $MockifySut->mockImported('Package::Name', 'ImportedFunctionName')->when(String())->thenReturn('Hello');
  $MockifySut->mockStatic('Fully::Qualified::FunctionName')->when(String())->thenReturn('Hello');
  $MockifySut->mockConstructor('Package::Name', $Object);#  hint: build this object also with Mockify
  my $PackageILikeToTest = $MockifySut->getMockObject();

  $PackageILikeToTest->do_something();# all injections are used here

  # verify that the mocked method were called
  ok(WasCalled($PackageILikeToTest, 'ImportedFunctionName'), 'ImportedFunctionName was called');
  done_testing();

DESCRIPTION

Use Test::Mockify::Sut to create and configure Sut objects. Use Test::Mockify::Verify to verify the interactions with your mocks.

You can find a Example Project in ExampleProject

METHODS

mock

To mock methods or functions of your Sut is a really bad idea. Therefore this method throws a Error when used.

mockImported

Sometimes it is not possible to inject the dependencies from the outside. This is especially the case when the package uses imports of static functions. mockImported provides the possibility to mock imported functions inside the mock.

Unlike mockStatic is the injection with mockImported only in the mock valid.

synopsis

  package Show::Magician;
  use Magic::Tools qw ( Rabbit );
  sub pullCylinder {
      shift;
      if(Rabbit('white')){
          return 1;
      }else{
          return 0;
      }
  }
  1;

In the Test it can be mocked

  package Test_Magician;
  use Magic::Tools qw ( Rabbit );
  my $Mockify = Test::Mockify::Sut->new( 'Show::Magician', [] );
  $Mockify->mockImported('Magic::Tools','Rabbit')->when(String('white'))->thenReturn(1);

  my $Magician = $Mockify->getMockObject();
  is($Magician ->pullCylinder(), 1);
  Rabbit('white');# return original result
  1;

It can be mixed with normal spy

spyImported

spyImported provides the possibility to spy imported functions inside the mock.

Unlike spyStatic is the injection with spyImported only in the mock valid.

synopsis

  package Show::Magician;
  use Magic::Tools qw ( Rabbit );
  sub pullCylinder {
      shift;
      if(Rabbit('white')){
          return 1;
      }else{
          return 0;
      }
  }
  1;

In the Test it can be mocked

  package Test_Magician;
  use Magic::Tools qw ( Rabbit );
  my $Mockify = Test::Mockify::Sut->new( 'Show::Magician', [] );
  $Mockify->spyImported('Magic::Tools','Rabbit')->when(String());

  my $Magician = $Mockify->getMockObject();
  is($Magician->pullCylinder(), 'SomeValue');
  is(GetCallCount($Magician, 'Rabbit'), 1);
  1;

It can be mixed with normal spy

mockStatic

Sometimes it is not possible to inject the dependencies from the outside. mockStatic provides the possibility to mock static functions inside the mock.

Attention: The mocked function is valid as long as the $Mockify is defined. If You leave the scope or set the $Mockify to undef the injected method will be released.

synopsis

  package Show::Magician;
  use Magic::Tools;
  sub pullCylinder {
      shift;
      if(Magic::Tools::Rabbit('black')){
          return 1;
      }else{
          return 0;
      }
  }
  1;

In the Test it can be mocked like:

  package Test_Magician;
  { # start scope
      my $Mockify = Test::Mockify::Sut->new( 'Show::Magician', [] );
      $Mockify->mockStatic('Magic::Tools::Rabbit')->when(String('black'))->thenReturn(1);
      $Mockify->spy('log')->when(String());
      my $Magician = $Mockify->getMockObject();

      is($Magician->pullCylinder('black'), 1);
      is(Magic::Tools::Rabbit('black'), 1); 
  } # end scope
  is(Magic::Tools::Rabbit('black'), 'someValue'); # The orignal method in in place again

It can be mixed with normal spy

ACKNOWLEDGEMENTS Thanks to @dbucky for this amazing idea

spyStatic

Provides the possibility to spy static functions around the mock.

synopsis

  package Show::Magician;
  sub pullCylinder {
      shift;
      if(Magic::Tools::Rabbit('black')){
          return 1;
      }else{
          return 0;
      }
  }
  1;

In the Test it can be mocked

  package Test_Magician;
  use Magic::Tools;
  my $Mockify = Test::Mockify::Sut->new( 'Show::Magician', [] );
  $Mockify->spyStatic('Magic::Tools::Rabbit')->whenAny();
  my $Magician = $Mockify->getMockObject();

  $Magician->pullCylinder();
  Magic::Tools::Rabbit('black');
  is(GetCallCount($Magician, 'Magic::Tools::Rabbit'), 2); # count as long as $Mockify is valid

  1;

It can be mixed with normal spy. For more options see, mockStatic

mockConstructor

Sometimes it is not possible to inject the dependencies from the outside. This method gives you the posibility to override the constructor of a package where your Sut depends on. The defaut constructor is new if you need another constructor name, use the third parameter.

Attention: The mocked constructor is valid as long as the Mockify object is defined. If You leave the scope or set the Mockify object to undef the injected constructor will be released.

synopsis

  package Path::To::SUT;
  use Path::To::Package;
  sub callToAction {
      shift;
      return Path::To::Package->new()->doAction();
  }
  1;

In the Test it can be mocked like:

  package Test_SUT;
  { # start scope
      my $MockifySut = Test::Mockify::Sut->new( 'Path::To::SUT', [] );
      $MockifySut->mockConstructor('Path::To::Package', $self->_createPathToPackage()); 
      my $Test_SUT = $MockifySut->getMockObject();

      is($Test_SUT->callToAction(), 'hello');
  } # end scope

  sub _createPathToPackage{
      my $self = shift;
      my $Mockify = Test::Mockify::Sut->new( 'Path::To::Package', [] );
      $Mockify->mock('doAction')->when()->thenReturn('hello');
      return $Mockify->getMockObject();
  }

It can be mixed with normal spy.

getVerificationObject

Provides the actual mock object, which you can use for verification. This is code sugar for the method getMockObject.

  my $Mockify = Test::Mockify::Sut->new( 'My::Module', [] );
  my $VerificationObject = $Mockify->getVerificationObject();
  ok(WasCalled($VerificationObject, 'FunctionName'));