1

有没有人经历过失败的单元测试,当他们尝试调试它以找出失败发生的位置时,在调试器中运行代码时单元测试成功?

我正在使用带有 EPIC 0.6.35 和 ActiveState ActivePerl 5.10.0 的 Eclipse 3.5.1。我用多个例程编写了模块 A 和模块 B。模块 B 中的一个例程从模块 A 调用一堆例程。我将模拟对象添加到我的模块 B 单元测试文件中,以尝试在模块 B 上获得更完整的代码覆盖率,其中模块 B 中的代码测试以查看所有调用模块 As 例程失败或成功。所以我在我的单元测试中添加了一些模拟对象来强制一些模块 A 例程返回失败,但我没有得到预期的失败。当我调试我的单元测试文件时,对模块 A 例程的调用确实按预期失败(并且我的单元测试成功)。当我在没有调试的情况下正常运行单元测试文件时,对模拟模块 A 例程的调用没有按预期失败(并且我的单元测试失败)。

这里会发生什么?如果我可以使用一小组简单代码使其失败,我将尝试发布我的问题的工作示例。

附录: 我把我的代码缩减到一个能证明我的问题的最低限度的集合。该问题的详细信息和工作示例如下:

我的 Eclipse 项目包含一个“lib”目录,其中包含两个模块 ... MainModule.pm 和 UtilityModule.pm。我的 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 并选择Run As | Perl Local,它给了我以下输出:

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.

当我右键单击同一个单元测试文件并选择Debug As | Perl Local,它给了我以下输出:

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 已经将其导出slurpFile到 MainModule之后将模拟版本安装到 UtilityModule 中。MainModule 使用的别名仍然指向原始版本。

要修复它,请将 MainModule 更改为使用完全限定的子例程名称:

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

这在调试器中起作用的原因是调试器使用符号表操作来安装挂钩。这些挂钩必须在正确的时间以正确的方式安装,以避免正常发生的不匹配。

有争议的是,只要代码在那里的行为与在调试器之外运行时的行为不同,它就是一个错误(在调试器中),但是当您有三个模块都与符号表混在一起时,事情可能表现得很奇怪也就不足为奇了。

于 2009-11-23T19:00:16.610 回答
0

您的模拟是否操纵符号表?我在调试器中看到了一个干扰符号表修改的错误。尽管在我的情况下,问题被逆转了;代码在调试器下中断,但在正常运行时工作。

于 2009-11-18T21:45:20.207 回答