为什么我的Perl单元测试在EPIC中失败,但在调试器中工作?

为什么我的Perl单元测试在EPIC中失败,但在调试器中工作?,perl,unit-testing,debugging,mocking,epic,Perl,Unit Testing,Debugging,Mocking,Epic,有没有人经历过单元测试失败,当他们试图调试它以找出失败发生的位置时,在调试器中运行代码时,单元测试成功了 我正在使用Eclipse3.5.1和Epic0.6.35以及ActiveState ActivePerl 5.10.0。我用多个例程编写了模块A和模块B。模块B中的一个例程调用模块A中的一组例程。我正在将模拟对象添加到模块B单元测试文件中,以尝试在模块B上获得更完整的代码覆盖率,模块B中的代码测试模块As例程的所有调用是失败还是成功。因此,我在单元测试中添加了一些模拟对象,以强制一些模块A例

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

我正在使用Eclipse3.5.1和Epic0.6.35以及ActiveState ActivePerl 5.10.0。我用多个例程编写了模块A和模块B。模块B中的一个例程调用模块A中的一组例程。我正在将模拟对象添加到模块B单元测试文件中,以尝试在模块B上获得更完整的代码覆盖率,模块B中的代码测试模块As例程的所有调用是失败还是成功。因此,我在单元测试中添加了一些模拟对象,以强制一些模块A例程返回失败,但我没有得到预期的失败。当我调试单元测试文件时,对模块A例程的调用确实如预期的那样失败(并且我的单元测试成功)。当我在没有调试的情况下正常运行单元测试文件时,对模拟模块A例程的调用不会像预期的那样失败(并且我的单元测试失败)

这到底是怎么回事?如果我能用一小部分简单的代码使它失败,我将尝试发布一个我的问题的工作示例

补遗:我将代码缩减到了一个简单的最小集,以证明我的问题。问题的详细信息和工作示例如下:

我的Eclipse项目包含一个带有两个模块的“lib”目录。。。main module.pm和utility module.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;  
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;   
UtilityModule.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;  
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;   
当我右键单击相同的单元测试文件并选择调试为|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.
slurpFile() encountered a problem!
ok 1 - force the Utility Module call to fail
1..1

所以,这显然是个问题。RunAs和Debug As应该给出相同的结果,对吧

模拟是否操纵符号表?我见过一个干扰符号表咀嚼的错误。虽然在我的情况下,问题是相反的;代码在调试器下中断,但在正常运行时工作。

模拟是否会操纵符号表?我见过一个干扰符号表咀嚼的错误。虽然在我的情况下,问题是相反的;代码在调试器下中断,但在正常运行时工作。

Exporter和Test::MockModule都通过操纵符号表来工作。这样做的事情并不总是很好地配合在一起。在这种情况下,Test::MockModule将在导出器已将其导出到MainModule之后,将模拟版本的
slurpFile
安装到UtilityModule中。MainModule使用的别名仍然指向原始版本

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

 my $file_contents = UtilityModule::slurpFile($file_name);
这在调试器中起作用的原因是调试器还使用符号表操纵来安装挂钩。这些挂钩必须以正确的方式在正确的时间安装,以避免正常情况下出现的不匹配


当代码在调试器中的行为与在调试器外部运行时的行为不同时,这是一个bug(在调试器中)是有争议的,但是当您有三个模块都在处理符号表时,事情可能会表现得异常也就不足为奇了。

Exporter和Test::MockModule都是通过操纵符号表来工作的。这样做的事情并不总是很好地配合在一起。在这种情况下,Test::MockModule将在导出器已将其导出到MainModule之后,将模拟版本的
slurpFile
安装到UtilityModule中。MainModule使用的别名仍然指向原始版本

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

 my $file_contents = UtilityModule::slurpFile($file_name);
这在调试器中起作用的原因是调试器还使用符号表操纵来安装挂钩。这些挂钩必须以正确的方式在正确的时间安装,以避免正常情况下出现的不匹配


当代码在调试器中的行为与在调试器外部运行时的行为不同时,这是一个bug(在调试器中)是有争议的,但是当您有三个模块都在处理符号表时,事情可能会表现得异常并不奇怪。

不,我的模拟例程只返回一个undef,这样我的错误处理代码就可以运行了。我在问题中添加了一个工作示例,希望一些聪明的Perl专家能够亲眼目睹我的问题,并告诉我如何解决它。我已经添加了另一个解决修改后的问题的答案,但我将此答案留作参考。不,我的模拟例程只返回一个undef,这样我的错误处理代码就可以运行了。我在问题中添加了一个工作示例,希望一些聪明的Perl专家能够亲眼目睹我的问题,并告诉我如何解决它。我已经添加了另一个解决修改后问题的答案,但我将此答案留作参考。太好了!谢谢现在我的声明覆盖范围在可接受的范围内!完美的谢谢现在我的声明覆盖范围在可接受的范围内!