gtest 总结
gtest without main
Google的C测试框架有两个输出库:一个是gtest.lib,另一个是gtest_main.lib。
依赖gtest.lib 需要实现自己的入口函数main
int main(int argc, char* argv[])
{testing::AddGlobalTestEnvironment(new FooEnvironment);::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); return 0;}
依赖gtest_main.lib 提供了测试应用程序入口点(即主要功能)的默认实现,添加编译依赖-l gtest_main
[Getting started with Google C++ Testing Framework](javascript:void())引用:
“[…] maybe you think that writing
all those main() functions is too much
work? We agree with you completely and
that’s why Google Test provides a
basic implementation of main(). If it
fits your needs, then just link your
test with gtest_main library and you
Gmock
C++ mock一个新类继承抽象类
使用MOCK_METHODx宏声明的类成员函数;详见 MOCK_METHOD*系列宏,参考如下博客
https://blog.csdn.net/songqier/article/details/79188237
使用EXPECT_CALL等一系列宏来指定这些函数在被调用时的动作。
在此基础上期望待测函数的输出
C mock 三种方式
方法一:利用C语言的预处理(在编译之前进行Mock)
#ifdef TESTING#define depend_func(account_no,item)\ function body\/* extend as function body during compile procedure, while the function name. so will not find the depend_func symble in ld process */#endif
方法二: 使用函数指针(编译期进行mock)
#ifdef TESTINGdepend_func= depend_func_mock
#elsedepend_func= depend_func_real
#endif
方法三: 在编译之后 Link时候进行替换
编写包括depend_func的库函数,在link的时候使用这个假的库函数
linux_gtest
linux下gtest的使用
环境配置(ubuntu 14.04 32bit)
直接去官方网站下载,可以下载最新的release版本
https://github.com/google/googletest
$ ./travis.sh$ cmake ./CMakeLists.txt$ make $ sudo make install### makefile.PHONY: all cleanCC=g++
OBJ_DIR=./obj
HEADERS=-I.
DEBUG=-g -ggdb
WALL=-Wall -W
CFLAGS=$(WALL) $(DEBUG)
L_CC=$(CC) $(CFLAGS) $(HEADERS)C_SRC=${wildcard *.cpp}
C_OBJ=$(patsubst %.cpp, $(OBJ_DIR)/%.o, $(C_SRC)) #目标文件
C_EXE=a.outall:prepare $(C_EXE)prepare:@if [ ! -d $(OBJ_DIR) ];then mkdir $(OBJ_DIR); fi$(C_EXE):$(C_OBJ)$(L_CC) $^ -o $@ -lgtest -lgtest_main -lpthread$(OBJ_DIR)/%.o:%.cpp$(L_CC) -c $< -o $@clean:@-rm -f $(C_EXE)@-rm -rf $(OBJ_DIR)
参数化
在测试时,经常需要考虑被测函数传入不同参数的值的情况。当然可以写很多的Assert或 EXPECT断言,但是是不是太多了,要写多少重复的的东西
比如
TEST(IsPrimeTest, HandleTrueReturn)
{EXPECT_TRUE(IsPrime(3));EXPECT_TRUE(IsPrime(5));EXPECT_TRUE(IsPrime(11));EXPECT_TRUE(IsPrime(23));EXPECT_TRUE(IsPrime(17));
}
参数化,采用一个较为通用的方法,你要测多少数据,自己加上就行了,不需要copy那么多一样的代码
class TestSqare:public testing::TestWithParam<int>{
protected:int Sqare(int a) {return a*a;}int a;
};TEST_P(TestSqare,case1){a = GetParam();EXPECT_EQ(a*a,Sqare(a));
}INSTANTIATE_TEST_CASE_P(Sare,TestSqare,testing::Values(1,2,3,4));int main(int argc,char* argv[])
{testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();
}
参考:https://blog.csdn.net/weixin_38988633/article/details/93312474
事件机制
gtest提供事件机制,主要是测试时候,可以在测试案例前后做一些操作
全局事件
要实现全局事件,必须写一个类,继承testing::Environment类,实现里面的SetUp和TearDown方法。
-
SetUp()方法在所有案例执行前执行
-
TearDown()方法在所有案例执行后执行
// 全局事件
class FooEnvironment : public testing::Environment
{
public:// 1. SetUp()方法在所有案例执行前执行virtual void SetUp();// 2. TearDown()方法在所有案例执行后执行virtual void TearDown();};void FooEnvironment::SetUp()
{std::cout << "Foo FooEnvironment SetUP" << std::endl;
}void FooEnvironment::TearDown()
{std::cout << "Foo FooEnvironment TearDown" << std::endl;
}int main(int argc, char* argv[])
{testing::AddGlobalTestEnvironment(new FooEnvironment);::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); //return 0;
}
死亡测试
“死亡”指的是程序的崩溃。通常在测试过程中,需要考虑到各种各样的输入,有的输入可能导致程序崩溃;或者某段程序本身存在内存泄漏,指针错误访问等崩溃现象,这时我们需要检查程序是否按照预期的方式挂掉,这也就是所谓的“死亡测试”。gtest的死亡测试能做到在一个安全的环境下执行崩溃的测试案例,同时又对崩溃结果进行验证。
具体会使用如下的两个宏
- ASSERT_DEATH(statement, regex`);
- EXPECT_DEATH(statement, regex`);
#include "gtest/gtest.h"int Add(int a,int b)
{return a + b;
}void FooDeath()
{int *pInt = NULL;*pInt = 2;
}void FooDeath2()
{
}// 正常测试
TEST(fun, Add)
{ EXPECT_EQ(1, Add(1,8)); EXPECT_EQ(10, Add(2,8)); EXPECT_EQ(40, Add(24,16));
}// gtest会优先运行死亡测试案例
TEST(FooDeathTest, Demo)
{EXPECT_DEATH(FooDeath(), "");
}// 死亡测试,当函数本身是正确的
TEST(Foo2DeathTest, Demo2)
{EXPECT_DEATH(FooDeath2(), "");
}int main(int argc, char* argv[])
{::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS();//return 0;
}
- 死亡测试时优先于正常的测试案例的,跟程序放的上下文位置没有关系,死亡测试请使用*DeathTest的测试名
- 死亡测试,如果真的是"死亡"的,那么会出现绿色的正常的RUN
- 死亡测试,如果不是真的“死亡”,会出现红色的“failed to die”
//*_EXIT(statement, predicate, regex`)
void func(int c)
{if(c <= 0)_exit(1);else _exit(2);
}TEST(ExitDeathTest, Demo)
{EXPECT_EXIT(func(-1), testing::ExitedWithCode(1),"");
}TEST(Exit2DeathTest, Demo2)
{EXPECT_EXIT(func(1), testing::ExitedWithCode(1),"");
}int main(int argc, char* argv[])
{::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS();//return 0;
}
运行参数
使用gtest编写的测试案例通常本身就是一个可执行文件,因此运行起来非常方便。同时,gtest也为我们提供了一系列的运行参数(环境变量、命令行参数或代码里指定),使得我们可以对案例的执行进行一些有效的控制。
gtest三种运行参数
- 系统环境变量
- 命令行参数
- 代码中指定FLAG
面能将特殊结果放入到一个xml文档中
int main(int argc, char* argv[])
{testing::GTEST_FLAG(output) = "xml:";::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS();
}
命令行参数
–gtest_list_tests
–gtest_list_tests 使用这个参数时,将不会执行里面的测试案例,而是输出一个案例的列表。
–gtest_filter 对执行的测试案例进行过滤,支持通配符
–gtest_filter=Exit*
运行所有测试案例名称为Exit开头的
通过命令行参数还能设置测试案例的输出
- 设置输出的一些颜色
- 打印出测试案例的执行时间(默认不打印)
- 将测试结果输出到另外的文件中(上文有实例)
通过命令行还能对案例异常进行处理
- 设置当案例失败时,如抛出异常,弹出对话框
- 调试模式下,案例失败时停止,方面调试
通过文件配置用例执行/* undo*/
自定义测试类
class MyTestClass : public ::testing::Test
{
public:MyTestClass() {}virtual ~MyTestClass() {}virtual void SetUp() {pCal = std::auto_ptr<Cal>(new Cal());}virtual void TearDown() {}
public:std::auto_ptr<Cal> pCal;
};// 第一个参数必须是类名MyTestClass
TEST_F(MyTestClass, test_add)
{pCal->setA(2);pCal->setB(3);EXPECT_TRUE(pCal->add() == 5);
}TEST_F(MyTestClass, test_sub)
{pCal->setA(2);pCal->setB(3);EXPECT_TRUE(pCal->sub() == -1);
}
代码框架
/* undo*/