Модуль Mocking Git, который используется внутри другого модуля - PullRequest
0 голосов
/ 19 сентября 2018

Я пытаюсь провести модульное тестирование моего модуля Importer::Git, который использует Git.pm из CPAN, и я хотел бы посмеяться над вызовами Git::command, Git::repository и Git::command_oneline и т. Д., Чтобы фактически не изменить мою файловую систему.Я пытался сделать это с помощью Test :: MockObject, но, похоже, я еще не полностью понял внутреннюю работу ...

Пример:

package Importer::Git

   sub create_repository {
    my ( $rc, $repo );

    $rc = Git::command_oneline( 'init', $self->targetdir . "/" . $self->name );                                                                                                                                                                                                      

    $repo = Git->repository( Directory => $self->targetdir . "/" . $self->name );
    $rc = $repo->command( 'config', 'user.name', $self->git_import_user->{ name } );

      $self->_repo( $repo );

      return $repo;
   }

Testcase:

use Import::Git;

use Test::More tests => 1;    # last test to print
use Test::Exception;
use Test::MockObject;

# pretend to have loaded the Git Module.
$INC{'Git.pm'} = 1;
my $git = Test::MockObject->new();
$git->fake_module('Git', repository => sub { $git } );
$git->set_true( qw(command command_oneline) );


$repo = Import::Git->init();
$repo->targetdir('./');
$repo->name('testrepo');
$repo->git_import_user({ name => 'test', email => 'test@test.com', push_default => 'testpush' });
$repo->create_repository();

Но, похоже, он не заменяет рассматриваемый объект git, так как этот тест дает сбой с сообщениями самого модуля Git.pm.

error: Malformed value for push.default: testpush
error: Must be one of nothing, matching, simple, upstream or current.
fatal: bad config variable 'push.default' in file '/home/.../testrepo/.git/config' at line 10
init .//testrepo: command returned error: 128

Я полагаю, в этих двух строках из Importer:: Git, это не заменяет $ repo

    $repo = Git->repository( Directory => $self->targetdir . "/" . $self->name );
    $rc = $repo->command( 'config', 'user.name', $self->git_import_user->{ name } );

Так как бы я это правильно высмеял?Я бы хотел, чтобы $repo->command звонки просто возвращали 1.

ОБНОВЛЕНИЕ:

Дейвс догадался, что это правильно.Исправление кода для этого решило это:

use Test::More tests => 1;    # last test to print
use Test::Exception;
use Test::MockObject;

my $git;
BEGIN {
# pretend to have loaded the Git Module.
$DB::single=1;
$INC{'Git.pm'} = 1;
$git = Test::MockObject->new();
$git->fake_module('Git', repository => sub { $git } );
$git->set_true( qw(command command_oneline) );
}

use Import::Git;

 my $real_repo = Import::Git->init();
 $real_repo->targetdir('./');
 $real_repo->name('testrepo');
 $real_repo->git_import_user({ name => 'test', email => 'test@test.com', push_default => 'testpush' }); 
 $real_repo->create_repository();

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

Альтернатива Отличный ответ Дейва заключается в том, чтобы вообще не использовать функциональность fake_module, а вместо этого временно переписать конструктор, используя что-то вроде Sub :: Override .Я чувствую, что это дает более детальный контроль.

use Test::More;
use Test::MockObject;
use Sub::Override;
use Git (); # we need this so we can override it in case it hasn't been loaded yet

# test code ... 

{
    # this is our faked module
    my $git = Test::MockObject->new;
    $git->set_true( qw(command command_oneline) );

    # we will save the arguments to the constructor here for 
    # inspection in tests later
    my @constructor_args;

    # this will temporarily replace the constructor until $sub
    # goes out of scope
    my $sub = Sub::Override->new(
        'Git::new' => sub {
            @constructor_args = @_; # save args
            return $git;            # return fake
        }
    );

    is something_that_deals_with_git(), $what_you_expect, 'test stuff with git';
    is scalar @constructor_args, 2, '... and Git constructor was called with 2 args';
    # ...
}

У него есть недостаток, заключающийся в том, что вы не можете использовать средства Test :: MockObject для просмотра вызовов от до new, но есть простоеспособ смягчить это с помощью нашей @constructor_args переменной.Все остальное остается прежним.

0 голосов
/ 19 сентября 2018

Это всего лишь предположение, и у меня нет времени на его проверку ...

Документация для метода fake_module() гласит:

Помните, что это должно произойти до того, как фактический модуль сможет загрузить.Либо заверните его в блок BEGIN перед использованием, либо потребуйте, либо поместите его перед вызовом use_ok() или require_ok().

Я ожидаю, что ваш модуль (это называется Import::Git или * 1015)* Git.pm , so you need to call fake_module () `перед загрузкой вашего модуля. Так что-то вроде этого, возможно:

use Test::More tests => 1;    # last test to print
use Test::Exception;
use Test::MockObject;

my $git;

BEGIN {
  # pretend to have loaded the Git Module.
  $INC{'Git.pm'} = 1;
  $git = Test::MockObject->new();
  $git->fake_module('Git', repository => sub { $git } );
  $git->set_true( qw(command command_oneline) );
}

use Import::Git;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...