单元测试框架gtest学习(一)——初始gtest

前言

在上一节中,我们介绍了gtest的安装过程,本节我们介绍gtest的简单使用

googletest安装与使用-CSDN博客

被测函数

我们先写一个简单的函数

int add(const int &a, const int &b) { return a + b; }

这个函数的功能很简单,就是求两个数的和

测试案例

接下来我们编写一个测试案例,用于测试上述add函数

TEST(AddFuncTest, Should_3_Given_1_and_2) { EXPECT_EQ(add(1, 2), 3); }

这段代码是gtest的一个testcase,其功能是测试add函数计算的值是否符合我们的预期,我们拆解这段代码来看

首先看测试签名(我自己的叫法,哈哈哈哈)

TEST(AddFuncTest, Should_3_Given_1_and_2) 
  • TEST:这是gtest内置的一个宏,它有两个参数,分别为[TestSuitName,TestCaseName],事实上,这两个参数仅仅只是个字符串,用户可以任意写,他们的作用是为了标识一个测试,比如

    • AddTest:表示我们要测试的函数是add,一般这个参数用于表示我们要进行测试的对象

    • Should_3_Given_1_and_2:表示当我们给出的参数是1和2的时候,我们期望的值应该是3,一般这个参数用于表示我们要对测试对象的哪个功能进行测试

 接下来是测试体

EXPECT_EQ(add(1, 2), 3);
  • EXPECT_EQ:这也是gtest内置的一个宏,用于比较两个数是否相等,从代码字面上理解,这个宏就是判断add(1,2)计算后的结果是否等于3

事实上,gtest正式基于上述宏进行测试的,而类似EXPECT_EQ的宏其实是一个断言。

Google还包装了一系列EXPECT_* 和ASSERT_*的宏,而EXPECT系列和ASSERT系列的区别是:

    1. EXPECT_*  失败时,案例继续往下执行。

    2. ASSERT_* 失败时,直接在当前函数中返回,当前函数中ASSERT_*后面的语句将不会执行。

我们在下一篇文章中再详细讨论这些断言宏,本节的目的仅仅只是认识gtest,能让代码跑起来就ok

 编译运行

接下来就是编译运行代码

我们先把目前写的代码全篇放出来

gTest.cc

#include <gtest/gtest.h>

int add(const int &a, const int &b) { return a + b; }

TEST(AddFuncTest, Should_3_Given_1_and_2) { EXPECT_EQ(add(1, 2), 3); }

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

对于主函数中对gtest的初始化以及运行,我们暂时记住就好,接下来编译代码

 g++ ./gTest.cc -o gtest -std=c++14 -lgtest -lpthread

结果查看

编译成功之后会生成可执行文件gtest,直接运行即可,以下是运行结果

 首先

[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.

这两行是提示信息,表示要开始运行gtest了,正在进行初始化工作

以下这段内容才是测试结果

[----------] 1 test from AddFuncTest
[ RUN      ] AddFuncTest.Should_3_Given_1_and_2
[       OK ] AddFuncTest.Should_3_Given_1_and_2 (0 ms)
[----------] 1 test from AddFuncTest (0 ms total)

其中以下行的结果表示正在运行AddFuncTest测试套件中的Should_3_Given_1_and_2测试案例(有关测试套件和测试案例的概念我们在后续文章中进行说明)

[ RUN      ] AddFuncTest.Should_3_Given_1_and_2

下述结果表示上述测试符合预期,并且测试执行时间为0ms

[       OK ] AddFuncTest.Should_3_Given_1_and_2 (0 ms)

接下来我们微微修改代码,让测试失败,查看结果与测试成功的结果有什么不同

int add(const int &a, const int &b) { return a + b; }

TEST(AddFuncTest, Should_3_Given_1_and_2) { EXPECT_EQ(add(1, 2), 4); }

我们将期望值修改为4,这显然是错误的,我们编译运行代码,直接看结果

从结果上看,我们的测试中出现了测试失败的案例,具体信息表现为

[ RUN      ] AddFuncTest.Should_3_Given_1_and_2
./gTest.cc:10: Failure
Expected equality of these values:
  add(1, 2)
    Which is: 3
  4

[  FAILED  ] AddFuncTest.Should_3_Given_1_and_2 (0 ms)

 从信息提示上看,在代码的第10行测试失败,测试期望的值应该是3,但是给出的值却是4,与预期不符

另一种运行方式

这里插一点题外,如果我们在代码中没有写main函数,其实也是可以编译运行的,只是需要我们手动在编译命令中链接gtest的main函数

也就是说,如果我们代码只有以下内容,没有写main函数

#include <gtest/gtest.h>

int add(const int &a, const int &b) { return a + b; }

TEST(AddFuncTest, Should_3_Given_1_and_2) { EXPECT_EQ(add(1, 2), 4); }

那么如果我们想编译成功,命令应该这样写

 g++ ./gTest.cc -o gtest -std=c++14 -lgtest -lpthread -lgtest_main

  我们用这种方式也可以成功编译代码

### 将 GTest 嵌入到其他 C++ 测试框架 #### 集成 GTest 到现有测试框架的方法 当考虑将 Google Test (GTest) 与其他 C++ 单元测试框架集成时,主要目标是在不破坏原有测试结构的前提下引入 GTest 的强大功能。这通常涉及几个方面的工作: - **兼容性评估**:确保两个框架之间不存在命名冲突或其他潜在的兼容性问题[^1]。 - **初始化顺序控制**:管理不同测试库之间的初始化次序,防止因依赖关系引发的问题。 - **结果聚合机制构建**:创建统的结果收集器来汇总来自多个源的数据报告。 具体实现上可以通过以下方式完成上述任务之——利用适配模式(Adapter Pattern),即通过编写层薄接口使两种风格各异却又相似度较高的 API 能够协同工作。例如,在某些情况下可以直接调用 GTest 提供的功能函数作为内部操作的部分;而在另些场景下则可能需要重新封装这些方法以便更好地适应外部环境的需求[^2]。 对于更深层次的融合,比如让 GMock(GTest 中用于模拟对象的部分)支持第三方断言宏定义或是自定义监听器等功能扩展,则往往涉及到修改或继承原生类以满足特定需求。这类改动虽然增加了复杂程度但也赋予了开发者更大的灵活性去定制专属解决方案[^3]。 ```cpp // 示例代码展示如何在个假定存在的另个测试框架中注册并执行gtest案例 #include <gtest/gtest.h> extern "C" { void register_test_case(void (*func)(void)); } int main(int argc, char *argv[]) { ::testing::InitGoogleTest(&argc, argv); // 注册个简单的测试用例给宿主框架 register_test_case([](){ TEST(MyFirstSuite, BasicAssertions) { EXPECT_EQ(1, 1); }; }); return RUN_ALL_TESTS(); } ``` 此段代码展示了怎样把基于 GTest 编写的单元测试嵌入至另种假设性的测试环境中运行。这里的关键在于找到合适的方式桥接两者间不同的启动逻辑与生命周期管理策略[^4]。 #### 注意事项 值得注意的是,并不是所有的组合都能完美契合,因此在实际应用过程中应当充分考虑到各种因素的影响,包括但不限于性能损耗、额外开销以及长期维护成本等问题。此外,由于各平台特性差异较大,所以在跨平台移植此类混合型方案时也需要格外小心谨慎[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值