2017-03-07 52 views
1

考慮其出口連接到互聯網,並返回結果的子程序模塊:如何嘲笑導入的子程序時,單元測試模塊

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賦值來實現,或者在Sub::OverrideTest::MockModule的幫助下更好。

但是在Perl 6中,模塊B的詞法範圍在完成編譯時關閉,因此在測試腳本運行時不能再修改(如果我錯了,請糾正)。所以這種方法似乎不可行。

那麼在Perl 6中如何解決這個任務呢?
I.e.如何編寫單元測試B::do-something,而不讓它叫真實A::download

回答

5

最簡單的方法可能是使用中描述的wrap,但是其先決條件是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 
+0

我不滿意這個答案。爲了模擬一個導入的子模塊,需要一個(通常是外部的)用'use soft'定義的模塊似乎是不合理的。是否真的沒有辦法修改A或B的符號表?如果不是,是否至少有一種方法來修改模塊'B'以使其更具可測性? –