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

一、前言

“死亡测试”名字比较恐怖,这里的“死亡”指的的是程序的崩溃。通常在测试过程中,我们需要考虑各种各样的输入,有的输入可能直接导致程序崩溃,这时我们就需要检查程序是否按照预期的方式挂掉,这也就是所谓的“死亡测试”。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`),我们可以非常方便的编写导致崩溃的测试案例,并且在不影响其他案例执行的情况下,对崩溃案例的结果进行检查。

Gtest:死亡测试的更多相关文章

  1. GoogleTest死亡测试的跨平台BUG

    最近工作用到了GoogleTest来作单元测试,但是死亡测试的ASSERT_DEATH语句一直跑不通. GoogleTest会启动子进程来运行代码,并捕捉子进程的错误消息,这就是所谓的"死亡 ...

  2. 使用Python把Gtest XML测试结果转换为HTML格式

    在最近的测试中,使用gtest测试框架对c语言代码进行测试,结果以XML文件来保存,但是测试结果的查阅和分析非常不方便.便想着把xml的结果直接转为HTML文件,方便和Jenkins系统对接显示.因现 ...

  3. [软件测试]Linux环境中简单清爽的Google Test (GTest)测试环境搭建(初级使用)

    本文将介绍单元测试工具google test(GTEST)在linux操作系统中测试环境的搭建方法.本文属于google test使用的基础教程.在linux中使用google test之前,需要对如 ...

  4. gtest以及测试小结

    所有的测试,都是让未知的东西和已知的东西进行比较,如果测试结果和预期的一样,那么就认为被测对象是OK的否则视为有问题. python的单元测试是写一堆继承了unittest.TestCase类,每个类 ...

  5. MFC程序使用GTest搭建测试框架

    一.起源 最近对单元测试比较感兴趣,之后就上网搜了一些测试的框架,C++项目使用的测试框架基本上都使用的GoogleTest,之后就开启了gtest的学习之路. 主要是根据<玩转Google开源 ...

  6. Linux下Google Test (GTest)测试环境搭建步骤

    1.下载GTEST 下载链接为:https://code.google.com/p/googletest/downloads/list 目前GTEST的最新版本为gtest-1.7.0.zip,因此我 ...

  7. gtest的安装和测试[good]

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

  8. gtest命令行测试案例

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

  9. GTest Google的一种白盒单元测试框架 开源项目

    GTest为google开源的白盒单元测试跨平台测试框架,含丰富的断言.类型参数化测试.死亡测试.以及其他的测试选项设置.文件保存等,以下将对该项目C++的实现进行简要的分析,作为学习记录备份. 基本 ...

随机推荐

  1. api-doc-php

    主要功能: 根据接口注释自动生成接口文档 演示地址 [Gitee Pages:]http://itxq.gitee.io/api-doc-php 开源地址: [GigHub:]https://gith ...

  2. 小于K的两数之和

    给你一个整数数组 A 和一个整数 K,请在该数组中找出两个元素,使它们的和小于 K但尽可能地接近 K,返回这两个元素的和. 如不存在这样的两个元素,请返回 -1. 示例1: 输入:A = [34,23 ...

  3. Java分布式:分布式锁之Zookeeper

    Java分布式:分布式锁之Zookeeper 分布式锁系列教程重点分享锁实现原理 引入ZooKeeper ZooKeeper是什么呢? ZooKeeper 是一个开源的分布式协调服务,它可以在分布式系 ...

  4. 【Spring Boot学习之十一】整合mongoDB

    环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2 参考: SpringBoot+Mongodb的使用

  5. [ARM-LInux开发]linux设备驱动makefile入门解析

    以下内容仅作参考,能力有限,如有错误还请纠正.对于一个普通的linux设备驱动模块,以下是一个经典的makefile代码,使用下面这个makefile可以完成大部分驱动的编译,使用时只需要修改一下要编 ...

  6. 【ARM-Linux开发】ARM嵌入式设备Linux系统启动步骤和方式

    1). 简介 本文简单介绍ARM嵌入式设备基于嵌入式Linux操作系统时候的启动步骤和启动方式, 区别与X86平台,ARM平台下并没有一个标准的启动步骤,不同ARM SoC都会使用各自定义的boot ...

  7. initramfs文件系统制作

    源码下载:https://busybox.net/downloads/ 源码版本:busybox-1.30.0.tar.bz2 [ 源码编译步骤 ] make menuconfig ARCH= COM ...

  8. Docker 容器内无法通过 HTTP 访问外网

    现象 内/外网 IP 和 域名 可以 ping 通 容器内无法访问宿主机所在内网及外网的 Web 服务(404) 通过 curl 查看返回头信息感觉是所有 Web 请求被中转到一个固定的 Nginx ...

  9. git pull时的冲突解决方式; git stash; git fetch

    git fetch指令: https://www.yiibai.com/git/git_pull.html 发现远端有更新,git pull时,如果你本地分支修改了东西,导致git pull有冲突,失 ...

  10. js实现html表格<td>标签中带换行的文本显示出换行效果

    遇见问题 如下内容中我写了几行,但是表格中并未按行显示,换行符反而变成了空格,于是想自己转换下 思考问题 1.可以看到表格的内容是后端传来的数据,于是想直接在后端转换下,把换行符替换成<br&g ...