转自:玩转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. UltraEdit 替换符

    1.在每行的最后一行添加字符串: 打开替换,在查找中输入 ^r  在替换栏中输入要替换的字符  再把下边的正则表达式勾选,然后开始或是全部替换就可以了 2.替换回车换行 在查找中输入 要替换的字符  ...

  2. netty-websocket-spring-boot-starter不同url端口复用

    netty-websocket-spring-boot-starter是一个基于netty的websocket服务端,目前笔者使用的版本依托于Springboot.官方网址https://github ...

  3. 安卓 App 性能专项测试之流畅度深度解析-上篇

    指标背景 流畅度,顾名思义是用户感知使用App页面时的流畅情况,"App卡不卡",这是用户最直接的感受. 但是要用量化之后的数据衡量流畅度,在Android平台这边并没有直接有效的 ...

  4. 在ensp上配置RIPv2的认证

    原理 实验模拟 实验拓扑 测试连通性 搭建rip网络 查看路由表 R3模拟攻击首先把在自己的的ip通告网段 配置完成后查看一下路由表 可以看到已经非法获取R1R2的网段信息,那么现在我们R3可以向两个 ...

  5. 接口和抽象类的区别,注意JDK8的接口可以有实现。

    Java中,抽象类和接口有相似的地方.下面我们就来细说说接口和抽象类的异同. 首先是相同的地方: 1. 接口和抽象类都能定义方法和属性. 2. 接口和抽象类都是看作是一种特殊的类.大部分的时候,定义的 ...

  6. ECharts 避免变窄

    var roomPercentChart = echarts.init(document.getElementById('room_percent')); function ajaxGetRoomPe ...

  7. 006 SpringCloud 学习笔记2-----SpringCloud基础入门

    1.SpringCloud概述 微服务是一种架构方式,最终肯定需要技术架构去实施. 微服务的实现方式很多,但是最火的莫过于Spring Cloud了.SpringCloud优点: - 后台硬:作为Sp ...

  8. [Docker] Windows 宿主环境下,共享或上传文件到容器的方法

    需求如题. 解决方案1 - 挂载目录(适用于创建新的容器) 格式-v 容器目录 或 -v 本地目录:容器目录 范例Linux宿主环境下:使用镜像 nginx:latest,以后台模式启动一个容器,将容 ...

  9. Java开发笔记(一百五十一)Druid连接池的用法

    C3P0连接池自诞生以来在Java Web领域反响甚好,业已成为hibenate框架推荐的连接池.谁知人红是非多,C3P0在大型应用场合中暴露了越来越多的局限性,包括但不限于下列几点:1.C3P0管理 ...

  10. OpenLayers加载高德地图离线瓦片地图

    本文使用OpenLayers最新版本V5.3.0演示:如何使用OpenLayer加载谷歌地球离线瓦片地图.OpenLayers 5.3.0下载地址为:https://github.com/openla ...