sml*_*mls 2 unit-testing mocking perl6
考虑一个模块,它导出一个连接到Internet并返回结果的子例程:
unit module A;
sub download is export {
"result from internet" # Not the actual implementation, obviously.
}
Run Code Online (Sandbox Code Playgroud)
另一个导入并调用该子例程的模块:
use A; # imports &download into this lexical scope
unit module B;
sub do-something is export {
download().uc ~ "!!" # Does something which involves calling &download
}
Run Code Online (Sandbox Code Playgroud)
现在我想为模块编写单元测试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";
Run Code Online (Sandbox Code Playgroud)
问题是缺少魔法代码来覆盖子download
...
在Perl 5中,我认为使用glob赋值可以很容易地实现这一点,或者在Sub :: Override或Test :: MockModule的帮助下更好.
但是在Perl 6中,模块的词法范围在B
完成编译后关闭,因此在测试脚本运行时不再能够修改(如果我错了,请纠正我).所以这种方法似乎不可行.
那么如何在Perl 6中解决这个任务呢?
即如何编写单元测试B::do-something
,而不让它调用真实A::download
?
最简单的方法可能是使用https://docs.perl6.org/language/functions#Routines中wrap
描述的方法,但前提条件是阻止内联的pragma.您需要在模块A中:use soft;
use soft;
unit module A;
use soft;
sub download is export {
"result from internet";
}
Run Code Online (Sandbox Code Playgroud)
模块B:
unit module B;
use A;
sub do-something is export {
download.uc ~ "!!";
}
Run Code Online (Sandbox Code Playgroud)
和测试脚本:
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
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
342 次 |
最近记录: |