一、前言

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

二、使用的宏

Fatal assertion Nonfatal assertion Verifies
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
\\d matches any decimal digit
\\D matches any character that's not a decimal digit
\\f matches \f
\\n matches \n
\\r matches \r
\\s matches any ASCII whitespace, including \n
\\S matches any character that's not a whitespace
\\t matches \t
\\v matches \v
\\w matches any letter, _, or decimal digit
\\W matches any character that \\w doesn't match
\\c matches 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)
xy matches 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`),我们可以非常方便的编写导致崩溃的测试案例,并且在不影响其他案例执行的情况下,对崩溃案例的结果进行检查。

Google开源C++单元测试框架gTest 5:死亡测试相关推荐

  1. 玩转Google开源C++单元测试框架

    玩转Google开源C++单元测试框架Google Test系列(gtest)(总) 前段时间学习和了解了下Google的开源C++单元测试框架Google Test,简称gtest,非常的不错. 我 ...

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

    一.前言 "死亡测试"名字比较恐怖,这里的"死亡"指的的是程序的崩溃.通常在测试过程中,我们需要考虑各种各样的输入,有的输入可能直接导致程序崩溃,这时我们就需要 ...

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

    一.前言 上一篇我们分析了gtest的一些内部实现,总的来说整体的流程并不复杂.本篇我们就尝试编写一个精简版本的C++单元测试框架:nancytest ,通过编写这个简单的测试框架,将有助于我们理解g ...

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

    一.前言 "深入解析"对我来说的确有些难度,所以我尽量将我学习到和观察到的gtest内部实现介绍给大家.本文算是抛砖引玉吧,只能是对gtest的整体结构的一些介绍,想要了解更多细节 ...

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

    一.前言 在设计测试案例时,经常需要考虑给被测函数传入不同的值的情况.我们之前的做法通常是写一个通用方法,然后编写在测试案例调用它.即使使用了通用方法,这样的工作也是有很多重复性的,程序员都懒,都希望 ...

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

    一.前言 使用gtest编写的测试案例通常本身就是一个可执行文件,因此运行起来非常方便.同时,gtest也为我们提供了一系列的运行参数(环境变量.命令行参数或代码里指定),使得我们可以对案例的执行进行 ...

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

    一.前言 本篇将介绍一些gtest的基本使用,包括下载,安装,编译,建立我们第一个测试Demo工程,以及编写一个最简单的测试案例. 二.下载 如果不记得网址, 直接在google里搜gtest,第一个 ...

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

    一.前言 gtest提供了多种事件机制,非常方便我们在案例之前或之后做一些操作.总结一下gtest的事件一共有3种: 1. 全局的,所有案例执行前后. 2. TestSuite级别的,在某一批案例中第 ...

  9. 玩转Google开源C++单元测试框架Google Test系列(gtest)(总)

    http://www.cnblogs.com/coderzh/archive/2009/04/06/1426755.html

  10. 玩转Google开源C++单元测试框架Google Test系列

    http://www.cnblogs.com/coderzh/archive/2009/04/06/1426755.html

最新文章

  1. 【“零起点”--百度地图手机SDK】如何添加地图图层+按钮事件+水平垂直布局?...
  2. 线程并发与进程并发各有什么you_操作系统问答题总结
  3. 修复Linux系统内核TCP漏洞,修复Linux TCP SACK PANIC 远程拒绝服务漏洞
  4. 解决YUM下Loaded plugins: fastestmirror Determining fastest mirrors 的问题
  5. 系统学习机器学习之算法评估
  6. Python中 ‘==‘ 与‘is‘ 以及它们背后的故事
  7. 从运营角度看待UE设计
  8. 事务管理基础:两段锁协议、活锁、死锁相关知识整理
  9. 将SQL-SERVER逆向工程导入Power-Design中并给表的字段添加注释
  10. python requests返回值为200 但是text无内容_手把手教你使用Python生成图灵智能小伙伴,实现工作助手闲聊功能
  11. 软件工程 - 个人博客系统 - 概要设计与详细设计文档
  12. table 样式美化
  13. LiveVideoStackCon2021 北京站专访:从上云到创新,视频云的新技术、新场景
  14. cad图纸问号怎么转换文字_CAD中文图纸中文字体变成问号怎么办?不慌这几步教你轻松解决...
  15. 计算机毕业设计、课程设计之[含论文+源码等]S2SH+mysql的报刊订阅系统[包运行成功]
  16. 百练_1664:放苹果_递归
  17. IT部门信息管理系统
  18. 计算机文件丢失系统无法启动,文件损坏或丢失windows无法启动_windows无法启动文件损坏解决方法...
  19. Termux 搭建 gogs
  20. jenkins插件下载镜像加速

热门文章

  1. mysql模拟大量数据
  2. microchip-02之MCC工具安装
  3. 解决使用Keil5不能生成bin文件或生成的是.bin文件夹问题
  4. 利用WireShark下载视频网站的流媒体视频
  5. 查询快递单号,自动识别快递公司
  6. JNI 方法大全及使用示例
  7. Cherry键盘外接Mac command按键失灵
  8. html怎么把盒子做成超链接,把整个DIV变成超链接
  9. 融资、上市,悦刻又在讲电子烟的未来
  10. 5个最佳团队交流应用程序