1

誰かが失敗した単体テストを経験したことがありますか?彼らがそれをデバッグして失敗が発生した場所を見つけようとしたときに、デバッガーでコードを実行すると単体テストが成功しますか?

Eclipse3.5.1とEPIC0.6.35およびActiveStateActivePerl5.10.0を使用しています。モジュールAとモジュールBの両方を複数のルーチンで作成しました。モジュールBのルーチンは、モジュールAから一連のルーチンを呼び出します。モジュールBのコードカバレッジを取得するために、モジュールBの単体テストファイルにモックオブジェクトを追加して、モジュールBのコードがすべてのモジュールの呼び出しルーチンが失敗または成功した場合。そこで、ユニットテストにいくつかのモックオブジェクトを追加して、モジュールAルーチンの一部に障害を返すように強制しましたが、期待どおりに障害が発生しませんでした。単体テストファイルをデバッグしたとき、モジュールAルーチンの呼び出しは期待どおりに失敗しました(そして単体テストは成功しました)。デバッグせずに通常どおり単体テストファイルを実行すると、モックされたモジュールAルーチンの呼び出しが期待どおりに失敗しません(単体テストが失敗します)。

ここで何が起こっているのでしょうか?簡単なコードの小さなセットを使用して問題を失敗させることができる場合は、問題の実用的な例を投稿しようと思います。

補遺: 問題を示す最小限のセットにコードを絞り込みました。問題の詳細と実際の例は次のとおりです。

私のEclipseプロジェクトには、MainModule.pmとUtilityModule.pmの2つのモジュールを含む「lib」ディレクトリが含まれています。私のEclipseプロジェクトには、トップレベルにMainModuleTest.tという名前の単体テストファイルと、ガベージテキストだけを含むinput_file.txtという名前のテキストファイルも含まれています。

EclipseProject/
    MainModuleTest.t
    input_file.txt
    lib/
        MainModule.pm
        UtilityModule.pm

MainModuleTest.tファイルの内容:

use Test::More qw(no_plan);
use Test::MockModule;
use MainModule qw( mainModuleRoutine );

$testName = "force the Utility Module call to fail";
# set up mock utility routine that fails
my $mocked = new Test::MockModule('UtilityModule');
$mocked->mock( 'slurpFile', undef );
# call the routine under test
my $return_value = mainModuleRoutine( 'input_file.txt' );
if ( defined($return_value) ) {
    # failure; actually expected undefined return value
    fail($testName);
}
else {
    # this is what we expect to occur
    pass($testName); 
}

MainModule.pmファイルの内容:

package MainModule;

use strict;   
use warnings; 
use Exporter; 
use base qw(Exporter); 
use UtilityModule qw( slurpFile );

our @EXPORT_OK = qw( mainModuleRoutine );

sub mainModuleRoutine {
    my ( $file_name ) = @_;
    my $file_contents = slurpFile($file_name);
    if( !defined($file_contents) ) {
        # failure
        print STDERR "slurpFile() encountered a problem!\n";
        return;
    }
    print "slurpFile() was successful!\n";
    return $file_contents;
}

1;  

UtilityModule.pmファイルの内容:

package UtilityModule;

use strict;   
use warnings; 
use Exporter; 
use base qw(Exporter); 

our @EXPORT_OK = qw( slurpFile );

sub slurpFile {
    my ( $file_name ) = @_;
    my $filehandle;
    my $file_contents = "";
    if ( open( $filehandle, '<', $file_name ) ) {
        local $/=undef;
        $file_contents = <$filehandle>;
        local $/='\n';
        close( $filehandle ); 
    }
    else {
        print STDERR "Unable to open $file_name for read: $!";
        return;    
    } 
    return $file_contents;
}

1;   

EclipseでMainModuleTest.tを右クリックし、[実行]、[実行]の順に選択します。Perlローカル、それは私に次の出力を与えます:

slurpFile() was successful!
not ok 1 - force the Utility Module call to fail
1..1
#   Failed test 'force the Utility Module call to fail'
#   at D:/Documents and Settings/[SNIP]/MainModuleTest.t line 13.
# Looks like you failed 1 test of 1.

同じ単体テストファイルを右クリックして、[名前を付けてデバッグ]、[名前を付けてデバッグ]の順に選択します。Perlローカル、それは私に次の出力を与えます:

slurpFile() encountered a problem!
ok 1 - force the Utility Module call to fail
1..1

したがって、これは明らかに問題です。実行とデバッグで同じ結果が得られるはずですよね?!?!?

4

2 に答える 2

1

ExporterとTest::MockModuleはどちらも、シンボルテーブルを操作することで機能します。それを行うことは、必ずしも一緒にうまく機能するとは限りません。この場合、Test :: MockModuleは、ExporterがすでにMainModuleにエクスポートしたslurpFile、モックバージョンのをUtilityModuleにインストールしています。MainModuleが使用しているエイリアスは、引き続き元のバージョンを指しています。

これを修正するには、完全修飾サブルーチン名を使用するようにMainModuleを変更します。

 my $file_contents = UtilityModule::slurpFile($file_name);

これがデバッガーで機能する理由は、デバッガーがシンボルテーブル操作使用してフックをインストールするためです。これらのフックは、通常発生する不一致を回避するために、適切な方法で適切なタイミングでインストールする必要があります。

コードがデバッガーの外部で実行されたときとは異なる動作をするときはいつでも(デバッガー内で)バグであると主張できますが、3つのモジュールがすべてシンボルテーブルをいじくり回している場合、物事が奇妙に動作する可能性があることは驚くべきことではありません。

于 2009-11-23T19:00:16.610 に答える
0

あなたのモックはシンボルテーブルを操作しますか? シンボル テーブルの変更を妨げるバグがデバッガーに見られました。私の場合、問題は逆になりましたが。コードはデバッガーの下で壊れましたが、正常に実行すると機能しました。

于 2009-11-18T21:45:20.207 に答える