对模块进行单元测试时如何模拟导入的子例程

2024-04-28

考虑一个导出连接到互联网并返回结果的子例程的模块:

unit module A;

sub download is export {
     "result from internet"  # Not the actual implementation, obviously.
}

另一个导入并调用该子例程的模块:

use A;  # imports &download into this lexical scope
unit module B;

sub do-something is export {
     download().uc ~ "!!"   # Does something which involves calling &download
}

现在我想为模块编写单元测试B.
但我不希望测试真正连接到互联网;我希望他们使用子例程的模拟版本download这是由我的测试脚本控制的:

use Test;
plan 2;

use B;

my $mock-result;
my &mock-download = -> { $mock-result }

# ...Here goes magic code that installs &mock-download
# as &download in B's lexical scope...

$mock-result = "fake result";
is do-something(), "FAKE RESULT!!", "do-something works - 1";

$mock-result = "foobar";
is do-something(), "FOOBAR!!", "do-something works - 2";

问题是缺少覆盖子的魔术代码download...

在 Perl 5 中,我认为使用 glob 赋值可以很容易地实现这一点,或者在以下命令的帮助下甚至更好子::覆盖 https://metacpan.org/pod/Sub::Override or 测试::模拟模块 https://metacpan.org/pod/Test::MockModule.

但在 Perl 6 中,模块的词法范围B编译完成后关闭,因此在测试脚本运行时不再可以修改(如果我错了,请纠正我)。所以这个方法看起来不太可能。

那么,如何在 Perl 6 中解决这一任务呢?
IE。如何编写单元测试B::do-something,而不让它调用真实的A::download?


最简单的方法可能是使用wrap中描述的https://docs.perl6.org/language/functions#Routines https://docs.perl6.org/language/functions#Routines但其前提条件是use soft;防止内联的杂注。你需要use soft;在模块A中:

unit module A;
use soft;

sub download is export {
    "result from internet";
}

模块B:

unit module B;
use A;

sub do-something is export {
    download.uc ~ "!!";
}

和测试脚本:

use Test;
use A;
use B;

&download.wrap({
    "mock result";
});

is do-something, "MOCK RESULT!!", "mock a 'use'd sub";
# ok 1 - mock a 'use'd sub
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对模块进行单元测试时如何模拟导入的子例程 的相关文章

随机推荐