玩转Google开源C++单元测试框架Google Test系列(gtest)之五 - 死亡测试

一、前言

“死亡测试”名字比较恐怖,这里的“死亡”指的的是程序的崩溃。通常在测试过程中,我们需要考虑各种各样的输入,有的输入可能直接导致程序崩溃,这时我们就需要检查程序是否按照预期的方式挂掉,这也就是所谓的“死亡测试”。gtest的死亡测试能做到在一个安全的环境下执行崩溃的测试案例,同时又对崩溃结果进行验证。

二、使用的宏
Fatal assertionNonfatal assertionVerifies
ASSERT_DEATH(statement, regex`);EXPECT_DEATH(statement, regex`);statement crashes with the given error
ASSERT_EXIT(statement, predicate, regex`);EXPECT_EXIT(statement, predicate, regex`);statement exits with the given error and its exit code matches predicate

 

由于有些异常只在Debug下抛出,因此还提供了*_DEBUG_DEATH,用来处理Debug和Realease下的不同。

三、*_DEATH(statement, regex`)

1. statement是被测试的代码语句

2. regex是一个正则表达式,用来匹配异常时在stderr中输出的内容

如下面的例子: 

复制代码
void  Foo()
{
    
int   * pInt  =   0 ;
    
* pInt  =   42  ;
}

TEST(FooDeathTest, Demo)
{
    EXPECT_DEATH(Foo(), 
"" );
}
复制代码

 

重要:编写死亡测试案例时,TEST的第一个参数,即testcase_name,请使用DeathTest后缀。原因是gtest会优先运行死亡测试案例,应该是为线程安全考虑。

四、*_EXIT(statement, predicate, regex`)

1. statement是被测试的代码语句

2. predicate 在这里必须是一个委托,接收int型参数,并返回bool。只有当返回值为true时,死亡测试案例才算通过。gtest提供了一些常用的predicate:

testing::ExitedWithCode(exit_code)


如果程序正常退出并且退出码与exit_code相同则返回 true

testing::KilledBySignal(signal_number)   //  Windows下不支持

 
如果程序被signal_number信号kill的话就返回true

3. regex是一个正则表达式,用来匹配异常时在stderr中输出的内容

这里, 要说明的是,*_DEATH其实是对*_EXIT进行的一次包装,*_DEATH的predicate判断进程是否以非0退出码退出或被一个信号杀死。

例子:

TEST(ExitDeathTest, Demo)
{
    EXPECT_EXIT(_exit(
1 ),  testing::ExitedWithCode( 1 ),   "" );
}

 

五、*_DEBUG_DEATH

先来看定义:

复制代码
#ifdef NDEBUG

#define  EXPECT_DEBUG_DEATH(statement, regex) \
  
do  { statement; }  while  ( false )

#define  ASSERT_DEBUG_DEATH(statement, regex) \
  
do  { statement; }  while  ( false )

#else

#define  EXPECT_DEBUG_DEATH(statement, regex) \
  EXPECT_DEATH(statement, regex)

#define  ASSERT_DEBUG_DEATH(statement, regex) \
  ASSERT_DEATH(statement, regex)

#endif    //  NDEBUG for EXPECT_DEBUG_DEATH
复制代码

 

可以看到,在Debug版和Release版本下, *_DEBUG_DEATH的定义不一样。因为很多异常只会在Debug版本下抛出,而在Realease版本下不会抛出,所以针对Debug和Release分别做了不同的处理。看gtest里自带的例子就明白了:

复制代码
int  DieInDebugElse12( int *  sideeffect) {
    
if  (sideeffect)  * sideeffect  =   12 ;
#ifndef NDEBUG
    GTEST_LOG_(FATAL, 
" debug death inside DieInDebugElse12() " );
#endif    //  NDEBUG
    
return   12 ;
}

TEST(TestCase, TestDieOr12WorksInDgbAndOpt)
{
    
int  sideeffect  =   0 ;
    
//  Only asserts in dbg.
    EXPECT_DEBUG_DEATH(DieInDebugElse12( & sideeffect),  " death " );

    #ifdef NDEBUG
    
//  opt-mode has sideeffect visible.
    EXPECT_EQ( 12 , sideeffect);
    
#else
    
//  dbg-mode no visible sideeffect.
    EXPECT_EQ( 0 , sideeffect);
    
#endif
}
复制代码

 

六、关于正则表达式

POSIX系统(Linux, Cygwin, 和 Mac中,gtest的死亡测试中使用的是POSIX风格的正则表达式,想了解POSIX风格表达式可参考: 

1. POSIX extended regular expression

2. Wikipedia entry.

在Windows系统中,gtest的死亡测试中使用的是gtest自己实现的简单的正则表达式语法。 相比POSIX风格,gtest的简单正则表达式少了很多内容,比如 ("x|y"), ("(xy)"), ("[xy]") 和("x{5,7}")都不支持。

下面是简单正则表达式支持的一些内容:


matches any literal character c
\\dmatches any decimal digit
\\Dmatches any character that's not a decimal digit
\\fmatches \f
\\nmatches \n
\\rmatches \r
\\smatches any ASCII whitespace, including \n
\\Smatches any character that's not a whitespace
\\tmatches \t
\\vmatches \v
\\wmatches any letter, _, or decimal digit
\\Wmatches any character that \\w doesn't match
\\cmatches any literal character c, which must be a punctuation
.matches any single character except \n
A?matches 0 or 1 occurrences of A
A*matches 0 or many occurrences of A
A+matches 1 or many occurrences of A
^matches the beginning of a string (not that of each line)
$matches the end of a string (not that of each line)
xymatches x followed by y

 

gtest定义两个宏,用来表示当前系统支持哪套正则表达式风格:

1. POSIX风格:GTEST_USES_POSIX_RE = 1 

2. Simple风格:GTEST_USES_SIMPLE_RE=1

七、死亡测试运行方式

1. fast方式(默认的方式)

testing::FLAGS_gtest_death_test_style  =   "fast " ;

2. threadsafe方式

testing::FLAGS_gtest_death_test_style  =   " threadsafe " ;


你可以在 main() 里为所有的死亡测试设置测试形式,也可以为某次测试单独设置。Google Test会在每次测试之前保存这个标记并在测试完成后恢复,所以你不需要去管这部分工作 。如:

复制代码
TEST(MyDeathTest, TestOne) {
  testing::FLAGS_gtest_death_test_style 
=   " threadsafe " ;
  
//  This test is run in the "threadsafe" style:
  ASSERT_DEATH(ThisShouldDie(),  "" );
}

TEST(MyDeathTest, TestTwo) {
  
//  This test is run in the "fast" style:
  ASSERT_DEATH(ThisShouldDie(),  "" );
}

int  main( int  argc,  char **  argv) {
  testing::InitGoogleTest(
& argc, argv);
  testing::FLAGS_gtest_death_test_style 
=   " fast " ;
  
return  RUN_ALL_TESTS();
}
复制代码

 

八、注意事项

1. 不要在死亡测试里释放内存。

2. 在父进程里再次释放内存。

3. 不要在程序中使用内存堆检查。

九、总结

关于死亡测试,gtest官方的文档已经很详细了,同时在源码中也有大量的示例。如想了解更多的请参考官方的文档,或是直接看gtest源码。

简单来说,通过*_DEATH(statement, regex`)和*_EXIT(statement, predicate, regex`),我们可以非常方便的编写导致崩溃的测试案例,并且在不影响其他案例执行的情况下,对崩溃案例的结果进行检查。

系列链接:

1.玩转Google开源C++单元测试框架Google Test系列(gtest)之一 - 初识gtest

2.玩转Google开源C++单元测试框架Google Test系列(gtest)之二 - 断言

3.玩转Google开源C++单元测试框架Google Test系列(gtest)之三 - 事件机制

4.玩转Google开源C++单元测试框架Google Test系列(gtest)之四 - 参数化

5.玩转Google开源C++单元测试框架Google Test系列(gtest)之五 - 死亡测试 

6.玩转Google开源C++单元测试框架Google Test系列(gtest)之六 - 运行参数

7.玩转Google开源C++单元测试框架Google Test系列(gtest)之七 - 深入解析gtest

8.玩转Google开源C++单元测试框架Google Test系列(gtest)之八 - 打造自己的单元测试框架

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值