[C++] gtest入门教程

gtest

前言

本文重写自 使用GTEST编写C++测试用例进阶教程(GTEST advanced中文译文)

重写了部分名称. 并调整了部分内容的顺序, 并有所删减.

如下:

  • 测试类, 即派生于::testing::Test的自定义派生类的类
  • 测试分类名, 即未使用任何自定义测试类的测试的仅用于分类和筛选的名
  • 测试类名/分类名, 定义测试时所用的第一个参数的内容, 原名测试套件
  • 测试名, 定义测试时所用的第二个参数的内容
  • 崩溃测试, 原名死亡测试
  • 检查, 即ASSERT和EXPECT和统称
  • 断言, 即ASSERT
  • 期望, 即EXPECT
  • 检查函数, 原名谓词, 谓词函数
  • 失败, 即未通过,
  • 成功, 即通过.
  • n型检查函数, 原无此名, 因对函数签名有渐进性的要求, 为做区分而起
  • 值测试模板, 原名参数化测试, 由于实际意义类似于模板而改名以模板为名称后缀
  • 类型测试模板, 原名类型测试, 改名理由同上

注意, 每个测试既不是函数也不是类, 不应用测试函数等称呼. 而是专门用专有名词称呼.

使用

头文件和库

使用gtest需包含头文件 gtest/gtest.h, 并链接库 gtest_main.libgtest.lib.

编译库时注意到属性->代码生成设置运行库为/MT/MTd.

gtest开源地址为 github.com/google/googletest, 编译代码建议用Cmake生成VS项目, 然后用VS编译生成lib文件, 最后复制头文件和lib文件到项目里.注意编译时Release, Debug, Win32, x64的lib都不能错.

可用以下代码

#define GOOGLE_TEST_LIB_PATH "google_test/lib/"

#ifdef _WIN64
#define LIB_ARCH "x64"
#else
#define LIB_ARCH "x86"
#endif

#ifdef _DEBUG
#define LIB_COMPILER_MODE "d"
#else
#define LIB_COMPILER_MODE ""
#endif

#pragma comment(lib, GOOGLE_TEST_LIB_PATH "gtest"      LIB_COMPILER_MODE "." LIB_ARCH ".lib")
#pragma comment(lib, GOOGLE_TEST_LIB_PATH "gtest_main" LIB_COMPILER_MODE "." LIB_ARCH ".lib")
#pragma comment(lib, GOOGLE_TEST_LIB_PATH "gmock"      LIB_COMPILER_MODE "." LIB_ARCH ".lib")
#pragma comment(lib, GOOGLE_TEST_LIB_PATH "gmock_main" LIB_COMPILER_MODE "." LIB_ARCH ".lib")

快速添加要链接的lib文件.

命令行选项

对使用gtest编译生成的程序使用命令行参数--help, 可以查看可用的命令行选项.
本文 记录章 调试章 特殊测试章 都主要围绕命令行选项和环境遍历展开.

This program contains tests written using Google Test. You can use the
following command line flags to control its behavior:

Test Selection:
  --gtest_list_tests
      List the names of all tests instead of running them. The name of
      TEST(Foo, Bar) is "Foo.Bar".
  --gtest_filter=POSTIVE_PATTERNS[-NEGATIVE_PATTERNS]
      Run only the tests whose name matches one of the positive patterns but
      none of the negative patterns. '?' matches any single character; '*'
      matches any substring; ':' separates two patterns.
  --gtest_also_run_disabled_tests
      Run all disabled tests too.

Test Execution:
  --gtest_repeat=[COUNT]
      Run the tests repeatedly; use a negative count to repeat forever.
  --gtest_shuffle
      Randomize tests' orders on every iteration.
  --gtest_random_seed=[NUMBER]
      Random number seed to use for shuffling test orders (between 1 and
      99999, or 0 to use a seed based on the current time).

Test Output:
  --gtest_color=(yes|no|auto)
      Enable/disable colored output. The default is auto.
  --gtest_print_time=0
      Don't print the elapsed time of each test.
  --gtest_output=(json|xml)[:DIRECTORY_PATH\|:FILE_PATH]
      Generate a JSON or XML report in the given directory or with the given
      file name. FILE_PATH defaults to test_detail.xml.

Assertion Behavior:
  --gtest_break_on_failure
      Turn assertion failures into debugger break-points.
  --gtest_throw_on_failure
      Turn assertion failures into C++ exceptions for use by an external
      test framework.
  --gtest_catch_exceptions=0
      Do not report exceptions as test failures. Instead, allow them
      to crash the program or throw a pop-up (on Windows).

Except for --gtest_list_tests, you can alternatively set the corresponding
environment variable of a flag (all letters in upper-case). For example, to
disable colored text output, you can either specify --gtest_color=no or set
the GTEST_COLOR environment variable to no.

For more information, please read the Google Test documentation at
https://github.com/google/googletest/. If you find a bug in Google Test
(not one in your own code or tests), please report it to
<googletestframework@googlegroups.com>.

测试

普通测试

使用测试分类名和测试名定义一个测试.

TEST(分类名, 测试名) {
    测试代码
}

若编译器支持中文变量名, 分类名和测试名可使用中文.

然后使用下面套路化的main函数启动测试.

int main(int argc, char** argv) {
	testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

可在类中添加

FRIEND_TEST(分类名, 测试名);

声明一个测试为类的友元.

若无特殊需求, 可以略过以下部分内容, 直接转到 检查章. 使用普通测试和一些常用的检查即可快速开始做测试.

使用NuGet包管理器添加GoogleTestAdapter后, 可在测试->测试资源管理器处让VS自动管理gtest的所有测试.

自定义测试类

每个测试都将从测试类做派生, 并生成实例以进行测试.

使用TEST定义测试则默认从::testing::Test派生.

自定义测试类要求从::testing::Test派生.

从自定义测试类创建测试应使用TEST_F, 同时改分类名为类名, 例如下

TEST_F(类名, 测试名) {
    测试代码
}

测试中可用this访问当前测试的实例.

可在类中添加

friend class 类名;
FRIEND_TEST(类名, 测试名);

声明一个自定义测试类的测试为类的友元.

::testing::Test派生自定义测试类后, 有以下类函数可重载.

  • void SetUp(); 在测试创建时被调用
  • void TearDown(); 在测试结束时被调用
  • static void SetUpTestSuite() 在进程启动时调用一次
  • static void TearDownTestSuite() 在进程退出时调用一次

注意, 虽然各个测试的类都派生自一个测试类, 但由于是不同实例, 因此非静态数据皆不共享.

类内共享对象

同一个类内的测试间可以通过静态变量共享对象, 以避免被测对象的反复构造析构.

  1. 自定义测试类public继承::testing::Test
  2. 定义并实现 static void SetUpTestSuite()
  3. 定义并实现 static void TearDownTestSuite()
  4. 定义测试时用TEST_F取代TEST.

静态对象用 SetUpTestSuite 和 TearDownTestSuite 进行创建和销毁.

gtest将在所有测试开始前调用 SetUpTestSuite, 所有测试结束后调用 TearDownTestSuite.

注意!

  1. 只定义静态对象指针, 不要定义静态对象. 否则跨文件间的静态对象的初始化顺序不可控.
  2. 虽然同一个测试类的测试间不会并行进行, 但进行顺序不是固定的. 测试中不要修改共享对象. 若做更改也必须要在测试结束时撤销修改.
全局共享对象

可以给所有测试定义共享对象.

  1. 自定义类public继承 ::testing::Environment.
  2. 定义并实现 void SetUp().
  3. 定义并实现 void TearDown()
  4. RUN_ALL_TESTS()前用new为本类生成一个实例, 然后用 ::testing::AddGlobalTestEnvironment 注册为全局共享对象.

gtest将接管实例并在测试开始前依次调用 SetUp 并在测试结束时反序调用 TearDown 和 delete. 因此不用另行 delete.

自定义测试模板

值测试模板 参数化测试

参数化测试即定义一套测试模板, 并对测试模板输入不同的值作为模板参数以生成多个测试.

  1. 自定义测试类public继承 testing::TestWithParam<T>
  2. 在函数外用 INSTANTIATE_TEST_SUITE_P(数据注释, 类名, 数据生成器1, 数据生成器2...) 定义测试数据.
  3. 使用TEST_P取代TEST_FTEST定义测试模板.

gtest将以 数据注释 为测试名前缀, 测试数据序号 为测试名后缀 通过测试模板生成大量测试.

testing::TestWithParam<T> 即两个接口类 testing::WithParamInterface<T>testing::Test 的组合.

下面是数据生成器概览:

生成器名参数生成数据
Range(b, e, s=1)以s为步长生成[b, e)区间内的的数据
Values(v1, v2, …)简单枚举数据v1, v2, …
ValuesIn(a)枚举C数组a内的数据
ValuesIn©枚举STL容器c内的数据
ValuesIn(b, e)枚举迭代器b到e的数据
Bool()枚举true和false
Combine(g1, g2, …)枚举生成器g1, g2, …等的
所有数据的所有组合(笛卡尔积)
并用std::tuple捆绑输出

将测试类在头文件中声明后, INSTANTIATE_TEST_SUITE_P测试数据和TEST_P测试模板可以分在不同文件定义. 可用于制作测试数据接口.

类型测试模板

即定义一套测试模板, 输入不同的类型进行测试.

  1. 自定义测试类模板public继承::testing::Test. 模板应能接收一个类型.
  2. using Types = ::testing::Type<类型...>; 生成待测类型组合类型
  3. TYPED_TEST_SUITE(类名/分类名, Types)将待测类型组合类型绑定到测试类
  4. 使用 TYPED_TEST 取代 TEST_F 定义测试模板

自省/反射

使用以下代码获取当前测试的信息对象

const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();

测试外包括测试类的静态函数, 调用current_test_info返回空指针.

详见监听器

检查

可在测试中使用检查. 检查包括断言与期望.

测试里若无检查失败则测试通过.

除个别检查外, 所有检查都带前缀, 可在下述两项中二选一.

  • ASSERT_ : 断言, 不通过检查则中断测试, 当在测试外使用时要求函数返回void.
  • EXPECT_ : 期望, 不通过检查并不中断测试.

值检查

数值
后缀参数通过条件
TRUE©c == true
FALSE©c == false
EQ(a, b)a == b
NE(a, b)a != b
LT(a, b)a < b
LE(a, b)a <= b
GT(a, b)a > b
GE(a, b)a >= b
FLOAT_EQ(a, b)float型 a ≈ b
DOUBLE_EQ(a, b)double型 a ≈ b
NEAR(a, b, e)abs(a - b) <= e
HRESULT_SUCCEEDED(h)SUCCEEDED(h) == true
HRESULT_FAILED(h)FAILED(h) == true

浮点数的大小比较未直接提供, gtest提供了3型检查函数

  • ::testing::FloatLE
  • ::testing::DoubleLE

做浮点数大小检查. 使用方法例如下

EXPECT_PRED_FORMAT2(::testing::FloatLE, v1, v2);

对HRESULT的检查失败时, gtest将调用FormatMessageA显示HRESULT的解释.

C字符串
后缀参数通过条件
STREQ(a, b)C字符串相等
STRNE(a, b)C字符串不相等
STRCASEEQ(a, b)C字符串忽略大小写相等
STRCASENE(a, b)C字符串忽略大小写不相等
自定义值检查1 1型检查函数 简单函数检查

本检查可以是检查函数, 也可以是检查值.

当函数为测试员提供时, 为检查值.

1型检查函数要求返回值能隐式转为bool.

后缀参数通过条件
PRED1(f, v)bool(f(v)) == true
PRED2(f, v, w)bool(f(v, w)) == true
PRED3(f, v, w, x)bool(f(v, w, x)) == true
PRED4(f, v, w, x, y)bool(f(v, w, x, y)) == true
PRED5(f, v, w, x, y, z)bool(f(v, w, x, y, z)) == true
自定义值检查2 2型检查函数
  1. 定义返回值为 ::testing::AssertResult 的检查函数.
  2. 在检查通过的地方返回 ::testing::AssertionSuccess().
  3. 在检查不通过的地方返回 ::testing::AssertionFailure(), 返回前可对其使用 << 输出注释.
  4. 现可使用 EXPECT_TURE(f(v))ASSERT_TRUE(f(v)) 做自定义检查.

2型检查函数要求返回 ::testing::AssertResult.

例如下:

::testing::AssertionResult IsEven(int n) {
    if((n % 2) == 0) {
        return ::testing::AssertionSuccess();
    } else {
        return ::testing::AssertFailure() << n << "为奇数";
    }
}
EXPECT_TRUE(IsEven(4 + 3))

注释将加在检查失败时的非通过值后, 并括上括号.

  Actual: false (7为奇数)
Expected: true
自定义值检查3 3型检查函数
  1. 定义返回值为 ::testing::AssertResult 的检查函数. 函数的每个接收值的形参都在函数前面添加一个接收生成值的表达式的字符串(const char*)的形参.
  2. 在检查通过的地方返回 ::testing::AssertionSuccess().
  3. 在检查不通过的地方返回 ::testing::AssertionFailure(), 返回前可对其使用 << 输出注释.
  4. 现可该检查函数f使用 ASSERT_PRED_FORMATn(f, v...)EXPECT_PRED_FORMATn(f, v...) 做自定义检查.
后缀参数通过条件
PRED_FORMAT1(f, v)自定义
PRED_FORMAT2(f, v, w)自定义
PRED_FORMAT3(f, v, w, x)自定义
PRED_FORMAT4(f, v, w, x, y)自定义
PRED_FORMAT5(f, v, w, x, y, z)自定义

3型检查函数要求返回::testing::AssertResult, 而且要接收2n个参数, 其中前n个为C字符串(const char*).

一个符合要求的3型检查函数的签名如下:

::testing::AssertionResult f(
    const char* expr1,
    const char* expr2,
    ...
    const char* exprn,
    T1 val1,
    T2 val2,
    ...
    Tn valn);
gmock扩展检查

gmock提供了大量扩展检查. 使用gmock需包含头文件 gmock/gmock.h 并链接相应的库.

具体见 cook_book.md

类型检查

编译期类型检查

::testing::StaticAssertTypeEq<T1, T2>();

程序流检查

普通
名称参数通过条件
SUCCESS()绝对通过
FAIL()绝对不通过并中断测试
ADD_FAILURE()绝对不通过但不中断测试
ADD_FAILURE_AT(file, line)

在测试外使用时, FAIL要求函数返回void.

在不应该到达的地方使用FAIL.

异常
后缀参数通过条件
THROW({s}, e)s抛出e型异常
ANY_THROW({s})s抛出任意异常
NO_THROW({s})s不抛出异常
检查
后缀参数通过条件
NO_FATAL_FAILURE({s})s不发生检查失败

注意该检查只检查本线程的检查失败, 检查不到s中创建出来的其他线程中的失败.

崩溃

崩溃即程序内部无法阻止的直接的进程崩溃.

gtest将通过额外建立子进程进行崩溃测试. 而主进程不会运行会崩溃的代码. 因此请不要在崩溃测试中释放内存.

后缀参数通过条件
DEATH({s}, m)s中以退出码0崩溃且
stderr输出匹配m
DEATH_IF_SUPPORTED({s}, m)支持崩溃测试时,
s中以退出码0崩溃且
stderr输出匹配m
不支持崩溃测试时
只编译不运行
DEBUG_DEATH({s}, m)DEBUG下,
s中以退出码0崩溃且
stderr输出匹配m
其他编译模式下,
只运行s并恒通过
EXIT({s}, p, m)s中以退出方式p崩溃且
stderr输出匹配m

以上中m为弱化的正则表达式.

p可设定为以下值, 以设定退出方式.

  • ::testing::ExitedWithCode(c), 退出码为c
  • ::testing::KilledBySignal(s), 退出信号为s

建议崩溃测试的类名/分类名以DeathTest为后缀.

::testing::FLAGS_gtest_death_test_style可设定崩溃测试的方式, 有

  • “threadsafe”
  • “fast”

两种.

桩对象 (gmock)

gmock除了提供大量扩展检查外, 其主要功能是做对象模拟, 即建立桩对象.

当前在开发的对象依赖于另一个尚未开发的对象. 这样子当前正在开发的对象该如何测试?

可模拟一个桩对象供当前正在开发的对象调用以进行测试.

桩对象即模拟对象, 通过gmock, 可令桩对象的函数调用返回指定值(不仅如此), 用以辅助依赖于桩对象的对象的开发和测试.

具体见 cook_book.md

自定义对象的流输出

gtest支持使用EXPECT_EQ等对C++内置类型, 数组, STL容器做比较, 并在检查失败时, 可视化输出这些值.

  vec1
    Which is: { 1, 2, 3 }
  vec2
    Which is: { 3, 2, 1 }

对于自定义类型, 默认按字节逐个输出其内存值.

可为自定义类型重载<<运算符或定义PrintTo函数做输出自定义. 两者都有定义时优选后者.

函数签名要求如下:

std::ostream& operator<<(std::ostream&, const T&);
void PrintTo(const T&, std::ostream*);

其中T为自定义类型.

测试流程监听器

自定义监听器需继承testing::TestEventListenertesting::EmptyTestEventListener.

其中前者为全为纯虚函数的接口, 后者为每个接口函数都提供有空实现.

可重载函数按调用的时间顺序排列如下:

函数名形参注释
OnTestProgramStart(const UnitTest&)
OnTestIterationStart(const UnitTest&,
int iteration)
重复测试
OnEnvironmentsSetUpStart(const UnitTest&)
OnEnvironmentsSetUpEnd(const UnitTest&)
OnTestSuiteStart(const TestSuite&)
OnTestStart(const TestInfo&)
OnTestPartResult(const TestPartResult&)不能使用检查
OnTestEnd(const TestInfo&)
OnTestSuiteEnd(const TestSuite&)
OnEnvironmentsTearDownStart(const UnitTest&)
OnEnvironmentsTearDownEnd(const UnitTest&)
OnTestIterationEnd(const UnitTest&,
int iteration)
OnTestProgramEnd(const UnitTest&)
  • UnitTest 记录测试程序信息
  • TestSuite 记录测试类/分类信息
  • TestInfo 记录单个测试的信息
  • TestPartResult 记录单次检查的结果

gtest默认提供有监听器用以在控制台输出测试信息.

使用以下代码获取监听器列表

::testing::TestEventListeners& listeners =
::testing::UnitTest::GetInstance()->listeners();

用以下代码删除默认监听器

delete listeners.Release(listeners.default_result_printer())

UnitTest

TestSuite

TestSuite对象有以下函数

函数名参数返回类型注释
name()const char*类名/分类名
type_param()const char*类型测试模板获取类型名
should_run()bool是否有测试需要进行
successful_test_count()int测试通过数
skipped_test_count()int测试跳过数
failed_test_count()int测试失败数
reportable_test_count()int要记录的测试数
disabled_test_count()int测试禁用数
reportable_disabled
_test_count
()int要记录的禁用测试数
test_to_run_count()int预计进行的测试数
total_test_count()int总测试数
Passed()bool本测试类/分类测试通过
Failed()bool本测试类/分类测试未通过
elapsed_time()TimeInMillis测试用时
start_timestamp()TimeInMillis测试启动时间戳
GetTestInfo(int i)const TestInfo*获取第i个(0起计数)
测试的TestInfo
ad_hoc_test_result()const TestResult&所有测试结果

TestInfo

TestInfo对象有以下函数

函数名参数返回类型注释
test_suite_name()const char*类名/分类名
name()const char*测试名
type_param()const char*类型测试模板获取类型名
value_param()const char*值测试模板获取值字符串
file()const char*测试所在源码文件名
line()int测试所在行
is_in_another_shard()bool测试是否在其他测试线程中
should_run()bool测试是否需要进行
is_reportable()bool测试是否需要记录

TestPartResult

记录

输出文件

测试结果一般情况下在控制台输出

启动时添加以下命令行参数或添加环境变量可以增加记录到文件的输出

输出为json, 字符编码为utf-8, 使用命令行参数

--gtest_output="json:<文件路径>"

或设置环境变量

set GTEST_OUTPUT=json:<文件路径>

输出为xml, 字符编码为ansi(gbk), 使用命令行参数

--gtest_output="xml:<文件路径>"

或设置环境变量

set GTEST_OUTPUT=xml:<文件路径>

也可省略:<文件路径>, 输出文件将默认为test_detail.xmltest_detail.json, 如下

--gtest_output="xml"
--gtest_output="json"

若文件已存在, 则会覆盖.

XML记录

XML记录的结构为

<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="1" failures="1" disabled="0" errors="0" time="0.113" timestamp="2020-05-05T14:05:31" name="AllTests">
  <testsuite name="类名/分类名" ... >
    <testcase name="测试名" status="run" result="completed" time="0.107" timestamp="2020-05-05T14:05:31" classname="所属的类名/分类名">
      <failure message="失败信息" type="">
        <![CDATA[失败信息]]>
      </failure>
      ...
      <properties>
        <property name="自定义记录的键" value="自定义记录的值"/>
        ...
      </properties>
    </testcase>
  </testsuite>
  ...
</testsuites>

文件的实际编码为ANSI(gbk), 与首行声明utf-8不符.

JSON记录

JSON记录的结构为

{
  "tests": 1,
  "failures": 1,
  "disabled": 0,
  "errors": 0,
  "timestamp": "2020-05-05T14:06:29Z",
  "time": "0.112s",
  "name": "AllTests",
  "testsuites": [
    {
      "name": "类名/分类名",
      "tests": 1,
      "failures": 1,
      "disabled": 0,
      "errors": 0,
      "timestamp": "2020-05-05T14:06:29Z",
      "time": "0.107s",
      "testsuite": [
        {
          "name": "测试名",
          "status": "RUN",
          "result": "COMPLETED",
          "timestamp": "2020-05-05T14:06:29Z",
          "time": "0.106s",
          "classname": "测试所属的类名/分类名",
          "key": "value", // 自定义记录
          ...
          "failures": [
            {
              "failure": "失败信息",
              "type": ""
            },
            ...
        },
        ...
    },
    ...
}

添加自定义记录

可用::testing::Test::RecordProperty记录属性数据到xmljson.

两个重载

RecordProperty(const string& key, int value);
RecordProperty(const string& key, const string& value);

调试

检查失败时断点

启动前添加命令行参数 --gtest_break_on_failure 或添加环境变量 set GTEST_BREAK_ON_FAILURE 可在检查失败时断点调试.

检查失败时抛出异常

启动前添加命令行参数 --gtest_throw_on_failure 或添加环境变量 set GTEST_THROW_ON_FAILURE 可在检查失败时抛出异常.

异常

默认情况下gtest接收测试中的一切异常, 同时终止当前测试, 接着并继续其他测试.

使用命令行参数 --gtest_catch_exceptions=0 或设置环境变量 set GTEST_CATCH_EXCEPTIONS=0 可调整gtest, 使其不接收测试中的异常, 而任其由系统接收, 以便让系统启动调试器进行调试.

特殊测试

测试筛选器

可只进行部分测试.

启动程序时提供命令行参数 --gtest_list_tests 可以显示所有测试的完整名称, 以便进行测试过滤.

在命令行参数--gtest_filter中用匹配模式可筛选测试

--gtest_filter=<匹配模式>

匹配模式语法如下, 其中 {} 表示0到任意个, [] 表示0或1个.

[ <正匹配单元> { ':' <正匹配单元> } ] [ '-' <负匹配单元> { ':' <负匹配单元> } ]

匹配单元中的特殊字符如下

  • * 匹配0到任意个任意字符
  • ? 匹配1个任意字符

匹配模式将筛选出所有能匹配任意正匹配单元且不匹配所有负匹配单元的测试, 以进行测试.

默认的匹配模式是 *

下面提供几个匹配模式的例子:

  • *Null*:*Constructor* 测试名或测试类/分类中含Null或Constructor的所有测试
  • -*DeathTest.* 运行所有非崩溃测试
  • FooTest.*-FooTest.Bar FooTest测试类/分类中除Bar外的所有测试

测试禁用标记

为测试名添加DISABLED_前缀能暂时禁用测试. 例如下

TEST(分类名, DISABLED_测试名) {
    测试代码
}

测试结束时只会提醒有测试被禁用

  YOU HAVE 2 DISABLED TESTS

但亦可添加命令行参数 --gtest_also_run_disabled_tests 无视禁用标记.(但仍可被筛选器筛选)

重复测试

可使用命令行参数 --gtest_repeat=<>重复数 进行重复测试.

重复测试有相应的监听器事件 OnTestIterationStart 和 OnTestIterationEnd.

乱序测试

可使用命令行参数 --gtest_shuffle 进行乱序测试.

可附加命令行参数 --gtest_random_seed=<数字> 设定随机数种子.

乱序测试时, 默认以启动时间为种子.(会将种子显示在首行以免无法重现一些依赖于特定次序的错误).

gtest缺陷解决方案

语句块标记

可定义普通函数以让测试多次调用.

当函数内检查未通过时, 打印的检查信息会只含该子函数内的失败出现所在的行, 而不能反映是在测试的哪次函数调用出现检查未通过.

使用语句块标记可以标记某次函数调用

SCOPED_TRACE("标记信息");

例如下:

{
    SCOPED_TRACE("标记信息");
    f();
}
{
    SCOPED_TRACE("标记信息");
    f();
}

断言失败扩散

普通函数中的ASSERT失败只会导致函数返回, 而不会引起调用该函数的测试终止.

弥补缺陷需要让断言失败扩散, 有以下三种方法.

HasFatalFailure

初始 HasFatalFailure 和 HasNonFatalFailure 皆返回 false

ASSERT失败使HasFatalFailure返回true
EXPECT失败使HasNonFatalFailure返回true

若出现过ASSERT失败或EXPECT失败HasFailure都将返回true

在函数调用结束后测试内使用以下代码结束测试

if(HasFatalFailure()) return;

在TEST和TEST_F外使用上述函数时需要加::testing::Test::前缀.

ASSERT_NO_FATAL_FAILURE

对函数使用 ASSERT_NO_FATAL_FAILURE 可以扩散普通函数中的ASSERT失败. 但会记录两次断言失败.

注意该检查只检查本线程的失败, 检查不到s中创建出来的其他线程中的失败.

在监听器中抛出断言失败异常

测试可以接住其内部抛出来的异常. 依此可令ASSERT失败时抛出异常实现扩散.

main函数中可以用函数

::testing::UnitTest::GetInstance()->listeners().Append

添加自定义监听器对象, gtest将在不同的时机依次调用各个监听器中的预设的重载函数.

下面自定义监听器并添加自定义监听器

  1. 监听器类继承testing::EmptyTestEventListener.
  2. 重载void OnTestPartResult(const testing::TestPartResult& result), 以监听各个检查的结果.
  3. 函数内用result.type() == testing::TestPartResult::kFatalFailure判断检查结果是否为断言失败, 是则抛出断言失败异常testing::AssertionException(result)
  4. 主函数中在所有其他监听器添加完后, 加上testing::UnitTest::GetInstance()->listeners().Append(new 监听器类).

例如下:

class ThrowListener : public testing::EmptyTestEventListener {
  void OnTestPartResult(const testing::TestPartResult& result) override {
    if (result.type() == testing::TestPartResult::kFatalFailure) {
      throw testing::AssertionException(result);
    }
  }
};
int main(int argc, char** argv) {
  ...
  testing::UnitTest::GetInstance()->listeners().Append(new ThrowListener);
  return RUN_ALL_TESTS();
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值