Linux项目搭建Gtest/Gmock框架总结 |
您所在的位置:网站首页 › gtest官方文档 › Linux项目搭建Gtest/Gmock框架总结 |
1. 前言
近期组里项目代码出于后期测试和长期维护的考虑,需要集成测试框架和用例补全,现有开源测试框架里面,google的test框架对于C++项目的支持度较高,且官方文档的完善性也高,便于上手,所以选用gtest这一套。 2. gtest环境搭建 下载地址:https://github.com/google/googletest/ 环境搭建:Git下来的源码里面包含了googletest和googlemock的文件夹,如果是做简单的gtest学习可以直接cmake编译就可以直接使用。如果需要加入到自己的C++项目中,需要编写Cmake文件,生成gtest/gmock静态库,再将编写的测试用例链接库就可以使用。我当前使用的目录结构如下图: 表示重复运行相同的测试用例两次,如果测试失败,会自动调用调试器。 命令行参数:运用–gtest_filter来过滤case。有时候我们并不需要运行所有测试,尤其是在修改的代码只影响某几个模块的情况下。为了支持运行一部分测试,Google 提供 --gtest_filter=,e.g. ./unittest --gtest_filter=* #执行所有测试 ./unittest --gtest_filter=PoissonUdpClientTest* #执行PoissonUdpClientTest开头的测试 ./unittest --gtest_filter=-PoissonUdpClientTest* #不执行PoissonUdpClientTest开头的测试 测试用例参数:利用DISABLED 关键词实现临时禁用测试 说明:只需在逻辑测试名或单元测试名前面加上 DISABLE_ 前缀,它就不会执行了,e.g. TEST(DISABLE_FooTest, DoSomething) 命令行参数:–gtest_also_run_disabled_tests,对于DISABLE的用例依然执行,e.g. ./unittest –gtest_also_run_disabled_tests 3. 编写测试用例 TEST使用常规的简单测试可以使用TEST宏,具体形式如下: // TestName表示本次测试的名称,第二个参数TestDecription用作描述,执行时控制台显示 TestName.TestDescription可以看到用例执行结果 TEST(TestName, TestDescription) { … }宏展开后的实质内容为TEST测试类: class TestName_ TestDescription_Test : public testing::Test { ... void TestBody() { … } ... }; 单元测试套件和TEST_F的使用在单元测试中,我们经常需要在某个测试套件、测试用例或者整个测试运行之前进行前置条件设置及检查,或者运行之后对运行结果进行校验等操作,包括初始化操作和资源回收等,谷歌提供了这样一套测试套件,下面举例说明。 class FooTest : public ::testing::Test { protected: //Override this to define how to set up the environment. virtual void SetUp() {} // Override this to define how to tear down the environment. virtual void TearDown() {} // shared resource initialize static void SetUpTestCase() {} // shared resource delete static void TearDownTestCase() {} };测试套件类经常需要使用到的接口主要是以上4个,需要继承::testing::Test类,重写SetUp()和TearDown()两个虚方法,在每个测试套件用例执行前会执行SetUp()的部分,在每个测试套件用例执行完之后会执行TearDown()的部分,主要用于每个执行用例的前置初始化和环境清除。 在测试套件的第一个测试用例开始前,SetUpTestCase函数会被调用,而在测试套件中的最后一个测试用例运行结束后,TearDownTestCase函数会被调用。适用场景主要是: 1)初始化数据涉及内存申请等操作,为每个测试实例构造对象将带来较大系统开销; 2)存在某数据,其在每个实例中均被用到,但每个实例都不会更改该数据的值。 有了上面的测试套件,接下来就只需写TEST_F测试用例了,形式参考 // 第一个参数必须为测试套件类名,第二个参数为测试描述 TEST_F(FooTest, FuncA) { Foo foo; foo.FuncA(); } 值参数化和TEST_P使用在测试用例中,我们时常需要传给被测函数不同的值,gtest为我们提供了简便的方法,可以使我们能够灵活的进行参数化测试。 这里直接给出最通用化场景值参数化的使用步骤: 将需要使用的多参数封装成一个参数类,如 //Step1:申明一个呼叫参数类,该类主要用于TEST_P宏中实现的测试逻辑使用 // 把需要用到两个参数封装成一个参数类 class CallArgs { public: CallArgs(int argOne, double argTwo) : m_argOne(argOne), m_argTwo(argTwo) {} int GetArgOne() { return m_argOne; } double GetArgTwo() { return m_argTwo; } private: int m_argOne; double m_argTwo; }; 申明一个呼叫类,该类类名同时也是TEST_P宏的第一个参数test_case_name // 该类继承了TestWithParam模版类,从而使得CallArgs类与Call类进行了关联。 class Call: public ::testing::TestWithParam { }; 使用INSTANTIATE_TEST_CASE_P宏,对Call类进行类相关多个的参数设置 // 这里只添加了两组参数,事实上,可以添加更多。 // 这里使用参数生成器::testing::Values,GTest定义了了很多参数生成器。 INSTANTIATE_TEST_CASE_P(VOIP, Call, ::testing::Values( CallArgs(2, 9.6), CallArgs(4, 14.5) ) ); 编写了使用TEST_P宏实现的测试用例 // 使用了TestWithParam类的GetParam()接口获取参数CallArgs // 实际上这是两个测试用例,即该代码段会执行两组用例 TEST_P( Call, makeCall) { CallArgs args = GetParam(); ASSERT_TRUE(makeCall(args.GetArgOne(), args.GetArgTwo())); } protected/private方法测试测试类的public方法,测试配置的输入一般为入参和成员变量的状态值,测试的输出一般为返回值和某些成员状态变化的值,但是类对象不能直接访问protected/private成员。 如果需要测试类的protected/private方法,我这里总结了3种方法: 首先一般不建议对非public成员函数直接访问,如果需要测试非public成员函数,可以被测试的类中新建一些public接口进行调用的方式; 可以在被测类的头文件中加入类似下面这种宏定义,将protected/private成员转为public访问类型 #ifdef FOR_GTEST #define private public #define protected public #endif然后在cmake文件中加入FOR_GTEST的编译宏,在测试代码中就可以直接访问调用 add_definitions(-DFOR_GTEST) 使用gtest框架的提供的FRIEND_TEST 在被测类的头文件需要引入包含该宏的头文件gtest/gtest_prod.h,然后添加宏进行友元声明,简单示例如下: // foo.h #include // Defines FRIEND_TEST. class Foo { ... private: FRIEND_TEST(FooTest, BarReturnsZeroOnNull); int Bar(void* x); }; // foo_test.cc ... TEST(FooTest, BarReturnsZeroOnNull) { Foo foo; EXPECT_EQ(0, foo.Bar(NULL)); // Uses Foo's private member Bar(). } gmock使用gmock是谷歌推出的开源白盒测试工具,用于编写C++模拟类的框架。通过gmock可以用一些简单的宏描述想要模拟的接口并指定其期望,在测试中有效地去除外部依赖,更方便地测试模块功能。 对类里面需要打桩的函数mock,语法如下: MOCK_METHODn(..., ...); //其中n表示参数的个数 MOCK_CONST_METHODn(..., ...); //const成员方法用这种对mock的方法可以指定期望,包括返回值,调用次数等,使用EXPECT_CALL()宏: EXPECT_CALL(mock_object, method(matchers)) .Times(cardinality) //可以指定调用几次 .WillOnce(action) //可以指定调用行为 .WillRepeatedly(action);Matchers指参数匹配器,可以指定任意参数,::testing::_ 表示输入的参数为任意参数,其他参数不一一列举 Mock virtual方法如下,不需要对工程代码做修改: // Foo.h class Foo { public: virtual int FooFuncOne(int num); }; // FooTest.cc class MockFoo : public Foo { public: MOCK_METHOD1(FooFuncOne, int(int num)); }; TEST(FooTest, FooFuncOne) { MockFoo mockFoo; // 指定FooFuncOne返回值为5 EXPECT_CALL(mockFoo, FooFuncOne((::testing::_))) .WillRepeatedly((::testing::Return)(5)); }上面mock方法主要用到了虚函数重写,但是对于非虚函数,上述写法是不能够生效的,需要有较大的改动,可以根据实际需要选择。下面贴了使用的示例: // foo.h class Foo { public: void CallSelfMethod(); void PublicMethod(); protected: void ProtectedMethod(); private: void PrivateMethod(); }; // 重构成模板类 foo_testable.h template class FooTestable { public: FooTestable(T &self); void CallSelfMethod(); void PublicMethod(); protected: void ProtectedMethod(); private: void PrivateMethod(); T &self; }; // foo_test.cc class MockFoo { public: MOCK_METHOD(PublicMethod, void()); MOCK_METHOD(ProtectedMethod, void()); MOCK_METHOD(PrivateMethod, void()); }; TEST(Test_MockSelfNonVirtualMethod, SelfMethod) { MockFoo mockFoo; FooTestable fooTestable(mockFoo); EXPECT_CALL(mockFoo, PublicMethod()).Times(1); EXPECT_CALL(mockFoo, ProtectedMethod()).Times(1); EXPECT_CALL(mockFoo, PrivateMethod()).Times(1); fooTestable.CallSelfMethod(); } 4. 常用断言宏 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |