Gtest:死亡测试
转自:玩转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:死亡测试的更多相关文章
- GoogleTest死亡测试的跨平台BUG
最近工作用到了GoogleTest来作单元测试,但是死亡测试的ASSERT_DEATH语句一直跑不通. GoogleTest会启动子进程来运行代码,并捕捉子进程的错误消息,这就是所谓的"死亡 ...
- 使用Python把Gtest XML测试结果转换为HTML格式
在最近的测试中,使用gtest测试框架对c语言代码进行测试,结果以XML文件来保存,但是测试结果的查阅和分析非常不方便.便想着把xml的结果直接转为HTML文件,方便和Jenkins系统对接显示.因现 ...
- [软件测试]Linux环境中简单清爽的Google Test (GTest)测试环境搭建(初级使用)
本文将介绍单元测试工具google test(GTEST)在linux操作系统中测试环境的搭建方法.本文属于google test使用的基础教程.在linux中使用google test之前,需要对如 ...
- gtest以及测试小结
所有的测试,都是让未知的东西和已知的东西进行比较,如果测试结果和预期的一样,那么就认为被测对象是OK的否则视为有问题. python的单元测试是写一堆继承了unittest.TestCase类,每个类 ...
- MFC程序使用GTest搭建测试框架
一.起源 最近对单元测试比较感兴趣,之后就上网搜了一些测试的框架,C++项目使用的测试框架基本上都使用的GoogleTest,之后就开启了gtest的学习之路. 主要是根据<玩转Google开源 ...
- Linux下Google Test (GTest)测试环境搭建步骤
1.下载GTEST 下载链接为:https://code.google.com/p/googletest/downloads/list 目前GTEST的最新版本为gtest-1.7.0.zip,因此我 ...
- gtest的安装和测试[good]
一.前言 本篇将介绍一些gtest的基本使用,包括下载,安装,编译,建立我们第一个测试Demo工程,以及编写一个最简单的测试案例. 二.下载 如果不记得网址, 直接在google里搜gtest,第一个 ...
- gtest命令行测试案例
使用gtest编写的测试案例通常本身就是一个可执行文件,因此运行起来非常方便.同时,gtest也为我们提供了一系列的运行参数(环境变量.命令行参数或代码里指定),使得我们可以对案例的执行进行一些有效的 ...
- GTest Google的一种白盒单元测试框架 开源项目
GTest为google开源的白盒单元测试跨平台测试框架,含丰富的断言.类型参数化测试.死亡测试.以及其他的测试选项设置.文件保存等,以下将对该项目C++的实现进行简要的分析,作为学习记录备份. 基本 ...
随机推荐
- api-doc-php
主要功能: 根据接口注释自动生成接口文档 演示地址 [Gitee Pages:]http://itxq.gitee.io/api-doc-php 开源地址: [GigHub:]https://gith ...
- 小于K的两数之和
给你一个整数数组 A 和一个整数 K,请在该数组中找出两个元素,使它们的和小于 K但尽可能地接近 K,返回这两个元素的和. 如不存在这样的两个元素,请返回 -1. 示例1: 输入:A = [34,23 ...
- Java分布式:分布式锁之Zookeeper
Java分布式:分布式锁之Zookeeper 分布式锁系列教程重点分享锁实现原理 引入ZooKeeper ZooKeeper是什么呢? ZooKeeper 是一个开源的分布式协调服务,它可以在分布式系 ...
- 【Spring Boot学习之十一】整合mongoDB
环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2 参考: SpringBoot+Mongodb的使用
- [ARM-LInux开发]linux设备驱动makefile入门解析
以下内容仅作参考,能力有限,如有错误还请纠正.对于一个普通的linux设备驱动模块,以下是一个经典的makefile代码,使用下面这个makefile可以完成大部分驱动的编译,使用时只需要修改一下要编 ...
- 【ARM-Linux开发】ARM嵌入式设备Linux系统启动步骤和方式
1). 简介 本文简单介绍ARM嵌入式设备基于嵌入式Linux操作系统时候的启动步骤和启动方式, 区别与X86平台,ARM平台下并没有一个标准的启动步骤,不同ARM SoC都会使用各自定义的boot ...
- initramfs文件系统制作
源码下载:https://busybox.net/downloads/ 源码版本:busybox-1.30.0.tar.bz2 [ 源码编译步骤 ] make menuconfig ARCH= COM ...
- Docker 容器内无法通过 HTTP 访问外网
现象 内/外网 IP 和 域名 可以 ping 通 容器内无法访问宿主机所在内网及外网的 Web 服务(404) 通过 curl 查看返回头信息感觉是所有 Web 请求被中转到一个固定的 Nginx ...
- git pull时的冲突解决方式; git stash; git fetch
git fetch指令: https://www.yiibai.com/git/git_pull.html 发现远端有更新,git pull时,如果你本地分支修改了东西,导致git pull有冲突,失 ...
- js实现html表格<td>标签中带换行的文本显示出换行效果
遇见问题 如下内容中我写了几行,但是表格中并未按行显示,换行符反而变成了空格,于是想自己转换下 思考问题 1.可以看到表格的内容是后端传来的数据,于是想直接在后端转换下,把换行符替换成<br&g ...