简单示例(Test宏)
#include "gtest/gtest.h"// 此函数用于判断入参是否为正整数:如果是,则返回0;否则,返回-1int Positive(int nNum) {if (nNum > 0) {return 0;} else {return -1;}}// 测试入参2是否为正整数/* Test()宏1. 第一个参数:是Test Case的名称2. 第二个参数:隶属于第一个Test Case的参数,即Test的名称一个测试的完整名称包括TestCase名称及Test名称不同Test Case的Test名称可以相同*/TEST(PositiveTest, HandlesPositiveInput){EXPECT_EQ(Positive(2), 0);}// 测试入参0是否为正整数TEST(PositiveTest, HandlesZeroInput){EXPECT_EQ(Positive(0), -1);}// 测试入参-2是否为正整数TEST(PositiveTest, HandlesNegativeInput){EXPECT_EQ(Positive(-2), -1);}int main(int argc, char **argv){// 分析gtest程序的命令行参数testing::InitGoogleTest(&argc, argv);// 调用RUN_ALL_TESTS()运行所有测试用例// main函数返回RUN_ALL_TESTS()的运行结果return RUN_ALL_TESTS();}
在上述代码中,我们编写了三个 test,分别为:HandlesPositiveInput、HandlesZeroInput 和 HandlesNegativeInput,这三个 test 都属于同一个 test case(PositiveTest)。
多个Test用同一套数据(TEST_F宏)
#include "gtest/gtest.h"//当我们想让多个test使用同一套数据配置时,就需要用到Test Fixtures//创建fixture的具体方法class FooTest: public testing::Test { //定义测试类FooTest//1. 创建一个类,并继承testing::test,并将该类中的一些内容声明为protected类型,以便在子类中进行访问protected://2. 根据实际情况,编写默认的构造函数或Setup函数,来为每个test准备所需内容void SetUp() {// 这里的代码将在构造函数之后立即被调用(就在每个测试之前)m_nTarget = 5;}//3. 根据实际情况,编写默认的析构函数或TearDown函数,来释放Setup()中分配的资源void TearDown() {//这里的代码将在每次测试之后立即被调用(就在析构函数之前)}public:int IsLargeThan5(const int & nNum);int m_nTarget;};// 判断入参是否大于5:如果是,则返回0;否则返回-1int FooTest::IsLargeThan5(const int & nNum){if (nNum > m_nTarget){return 0;}else{return -1;}}//4. 根据实际情况,定义test共享的子程序//当使用fixture时,我们使用TEST_F()宏代替TEST()宏,TEST_F()允许我们在test fixture中访问对象和子程序//TEST_F()的第一个参数(即 test case 的名称)必须是test fixture类的名字(即FooTest)TEST_F(FooTest, HandlesInput6)EXPECT_EQ(IsLargeThan5(6), 0);}TEST_F(FooTest, HandlesInput5) {EXPECT_EQ(IsLargeThan5(5), 0);}TEST_F(FooTest, HandlesInput4) {EXPECT_EQ(IsLargeThan5(4), -1);}int main(int argc, char **argv) {// 分析gtest程序的命令行参数::testing::InitGoogleTest(&argc, argv);// 调用RUN_ALL_TESTS()运行所有测试用例// main函数返回RUN_ALL_TESTS()的运行结果return RUN_ALL_TESTS();}
TEST_F的工作原理:
- 对于TEST_F()定义的每个test,googletest 将会在运行时创建一个新的test fixture
- 并立即通过 SetUp() 对其进行初始化,然后运行 test
- 之后通过调用 TearDown() 进行数据清理,最后删除 test fixture。
需要注意的是
- 同一个 test case 中不同的 test 具有不同的 test fixture 对象
- 并且 googletest 每次创建新的 test fixture 前都会先删除之前的 test fixture
- 多个 test 不会重用相同的 test fixture,某个 test 对 fixture 进行的修改对其他 test 无影响
在上述代码中,我们编写了三个 test,分别为:HandlesInput6、HandlesInput5 和 HandlesInput4,这三个 test 都属于同一个 test case(即 FooTest)。注意,这里的 test case(即 FooTest) 一定要是 test fixture 类。
上述代码中的 test 运行时,主要会进行如下操作:
- googletest 构造一个 FooTest 类的对象(我们称之为 f1);
- f1.SetUp() 函数对 f1 进行初始化;
- 使用对象 f1,运行第一个 test(HandlesInput6);
- f1.TearDown() 在 test 完成后,进行清理工作;
- 对象 f1 被析构。
- 上述5个步骤在另一个 FooTest 类的对象(如 f2)中重复,此次会运行 HandlesInput5。
Google Test
main()
编写 main() 函数时,要返回 RUN_ALL_TESTS() 宏的值。
main() 函数中的 ::testing::InitGoogleTest() 函数将会解析命令行中的 googletest 参数,它允许用户通过多样的命令行参数来控制测试程序的行为(即定制命令行参数的功能)。需要注意的是,::testing::InitGoogleTest() 函数必须要在 RUN_ALL_TESTS() 之前调用,否则对应的 flag 可能不会被正常地初始化。
RUN_ALL_TESTS()
在上面的代码示例中我们能够看到,调用 Test 的操作是通过 RUN_ALL_TESTS() 宏完成的。
- RUN_ALL_TESTS() 宏在所有 test 都成功时,返回0;否则返回1
- 需要注意的是,RUN_ALL_TESTS() 会运行所有关联的 test,这些 test 可以来自不同的 test case,甚至不同的源文件
当我们调用 RUN_ALL_TESTS() 宏的时候,会进行以下操作:
- 保存所有 googletest flag 的状态;
- 为第一个 test 创建一个 test fixture 对象;
- 通过 SetUp() 对上一步创建的 test fixture 对象进行初始化;
- 使用 test fixture 对象运行 test;
- 通过 TearDown() 清理 fixture;
- 删除 fixture;
- 还原所有 googletest flag 的状态;
- 为下一个 test 重复上述操作,直到所有的 test 执行完成。
注意:main() 函数必须要返回 RUN_ALL_TESTS() 宏的结果。同时,RUN_ALL_TESTS() 只能运行一次,多次调用会与 googletest 的一些功能(如 thread-safe death tests)发生冲突。
Google Test 是线程安全的,其线程安全特性要依赖 pthreads 库。
运行指定测试
int main(int argc, char **argv) {::testing::InitGoogleTest(&argc, argv);::testing::GTEST_FLAG(filter) = "Test_Cases1*";return RUN_ALL_TESTS();}
