2013-11-20 84 views
5

在工作中對我們的單元測試實現代碼覆蓋率的悲慘狀況,我想創建一個實用工具,將掃描我們的代碼庫和標記文件沒有100後%。我發現,得到所有的方法兩種方法:獲取的模塊中明確定義的方法/函數列表

訪問符號表直接:

for my $classname (@ARGV) { 
    eval "require $classname"; 
    die "Can't load $classname $EVAL_ERROR" 
     if $EVAL_ERROR; 

    no strict 'refs'; 
    METHODS: 
    for my $sym (keys %{ "${classname}::" }) { 
     next METHODS unless defined &{"${classname}::${sym}"}; 
     print "$sym\n"; 
    } 
} 

從CPAN使用Class::Inspector模塊:

for my $classname (@ARGV) { 
    my @methods = Class::Inspector->methods($classname, 'public'); 
    print Dumper \@methods; 
} 

這兩種方法產生類似的結果;這些問題在於它們顯示整個模塊可用方法的全部全部,而不僅僅是該模塊的內部的方法。

是否有某種方法來區分模塊可訪問的方法和模塊內部明確定義的方法?

注:我沒有嘗試創建一個完整的代碼覆蓋測試,對我的使用情況下,我只是想測試所有的方法被調用至少一次。像Devel::Cover這樣的完整覆蓋測試對我們來說是過分的。

+0

我不能在此刻驗證這一點,但我認爲你需要['can'](http://perldoc.perl.org/perlobj.html#The-UNIVERSAL-類): '打印 「$ _ \ n」 表示的grep $ classname->能($ _),鍵%{ 「$ {}類名::}」' – Zaid

+0

感謝您的評論,可惜的是'can'似乎還在查找繼承樹。我仍然從我們的一些自定義模塊獲取'Dumper'和其他方法的條目。 –

+0

你可以調用'local @PACKAGE :: NAME :: INC =();'然後執行'can()'檢查。 – frezik

回答

4

每個子(或更具體地,每個CV),記住哪些包它是在最初聲明測試用例:

Foo.pm

package Foo; 
sub import { 
    *{caller . "::foo"} = sub{}; 
} 
1; 

Bar.pm

package Bar; 
use Foo; 

our $bar; # introduces *Bar::bar which does not have a CODE slot 
sub baz {} 
1; 

訪問符號表現在給出foobaz。順便說一句,我會寫這樣的代碼(其原因將成爲在某一時刻清楚):

my $classname = 'Bar'; 
for my $glob (values %{ "${classname}::" }) { 
    my $sub = *$glob{CODE} or next; 
    say *$glob{NAME}; 
} 

接下來,我們來看看進入B module內省underlying C data structure。我們用B::svref_2object函數來做到這一點。這將產生一個B::CV對象,它具有方便STASH域(返回一個B::HV對象具有NAME場):

use B(); 
my $classname = 'Bar'; 
for my $glob (values %{ "${classname}::" }) { 
    my $sub = *$glob{CODE} or next; 
    my $cv = B::svref_2object($sub); 
    $cv->STASH->NAME eq $classname or next; 
    say *$glob{NAME}; 
} 

添加一些完整性檢查,這應該工作得很好。

動態類/模塊加載不應通過字符串eval完成。相反,我建議Module::Runtime

Module::Runtime::require_module($classname); 
+0

這也正是方法的類型我一直在尋找,謝謝!一些對'NAME'的調用是返回對象'B :: special',從文檔中不清楚這意味着什麼,但是我會忽略它們,因爲它們看起來都來自繼承樹的更高層 –

相關問題