资料html
偶然发现了google的测试框架gtest,立刻试了下,效果挺不错,特别是对于写c++的人来讲,方便不少。之前本身写c++的模块,一般是写好了模块后再另外定义些函数,而后在函数里面写测试用例来测试模块,若是测试点比较多,光是定义测试函数都要花费很多时间。gtest至关于大大节省了这个过程,用起来很是简单,直接用宏来定义测试用例,而且有不少丰富的宏来辅助测试,例如断言、预测值、死亡测试等。java
废话很少说,先上gtest的一些资料:linux
gtest的代码托管地址:https://github.com/google/googletest,用git clone下来就能够了。c++
使用gtest构建测试用例指导:https://github.com/google/googletest/tree/master/googletestgit
gtest英文文档:https://github.com/google/googletest/blob/master/googletest/docs/Documentation.mdgithub
gtest中文博客:玩转Google开源C++单元测试框架Google Test系列,这系列博客对gtest的具体使用讲解的很是详细。框架
gmock使用文档:https://github.com/google/googletest/blob/master/googlemock/docs/Documentation.md函数
gmock中文文档:Google Mock启蒙篇单元测试
gtest项目中包含了两个框架,一个gtest测试框架,一个是gmock框架。gtest相似于java里面的junit,用来作单元测试的;gmock主要是用来mock待测试模块依赖的一些对象,帮助你在测试中去除没必要要的依赖,相似与java的jMock和EasyMock。测试
好了,接下来直接上例子吧(注:下面的例子都是在linux下编译运行的,若是要在Windows上,须要看看gtest的文档)。
gtest demo
clone下来gtest后,能够在googletest目录中找到make目录:
,make目录中的Makefile是gtest帮咱们写好的一个使用gtest测试框架来测试模块的例子。咱们只须要把这个文件拷贝到写测试模块代码的目录,再改下面几个地方就能够编译运行测试模块。
1 GTEST_DIR = .. #设置gtest的项目目录 2 3 USER_DIR = ../samples #设置测试代码所在的目录 4 5 CPPFLAGS += -isystem $(GTEST_DIR)/include #设置预处理器参数 6 7 CXXFLAGS += -g -Wall -Wextra -pthread #设置编译器参数 8 9 TESTS = sample1_unittest #设置编译目标 10 11 。。。 12 13 #下面的目标生成规则改为测试模块的 14 15 sample1.o : $(USER_DIR)/sample1.cc $(USER_DIR)/sample1.h $(GTEST_HEADERS) 16 17 $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1.cc 18 19 sample1_unittest.o : $(USER_DIR)/sample1_unittest.cc \ 20 21 $(USER_DIR)/sample1.h $(GTEST_HEADERS) 22 23 $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1_unittest.cc 24 25 sample1_unittest : sample1.o sample1_unittest.o gtest_main.a 26 27 $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
上面都是make脚本的语法,不清楚的能够先Google下。好了,一块儿准备就绪后,来看看一个简单的例子。首先,先写个要测试的函数:
1 bool IsEven(int n) { 2 return (n % 2) == 0; 3 }
这是一个判断一个数是否为偶数的函数,是否是很是的简单~~下面咱们就来编写一个简单的测试案例:
1 TEST(IsEvenTest, EqTest) 2 { 3 EXPECT_FALSE(IsEven(1)); 4 EXPECT_TRUE(IsEven(2)); 5 }
上面能够看到,编写一个测试案例是多么的简单。咱们使用了TEST这个宏,它有两个参数,这两个参数的定义是:[TestSuiteName,TestCaseName],个人理解是TestSuiteName是对某个模块总案例名,TestCaseName是这个案例中某个case的名字。
对检查点的检查,咱们上面使用到了EXPECT_FLASE和EXPECT_TRUE这两个宏,这两个宏主要分别用来判断函数返回值是否为false和true。Google还包装了一系列EXPECT_* 和ASSERT_*的宏,而EXPECT系列和ASSERT系列的区别是:
1. EXPECT_* 失败时,案例继续往下执行。
2. ASSERT_* 失败时,直接在当前函数中返回,当前函数中ASSERT_*后面的语句将不会执行。
至于其它具体宏的介绍,能够经过上面给出的连接来查看。
好了,一块儿都准备好了,运行的结果是全部的测试都经过。
若是咱们把第一个EXPECT_FALSE改成EXPECT_TRUE的结果呢?答案是测试是失败的,并且会给出具体出错在文件中的哪一行,以及出错的缘由。
这是个很简单的使用gtest的例子,虽然简单,但基本涵盖了使用gtest的流程,并且用这些基本的功能就能解决大部分问题了。至于gtes的一些高级功能,须要的时候能够查上面连接中的文档。
gmock demo
编译运行的方式和gtest相似,Makefile文件在googlemock目录中的make目录中,按前面相似的修改这个Makefile文件就行。如今要测试的模块以下:
1 void func(FooInterface *p) 2 { 3 p->DoThis(); 4 }
这个模块依赖于实现了抽象类FooInterface的对象,FooInterface类定义以下:
1 class FooInterface { 2 public: 3 virtual ~FooInterface() {} 4 virtual void DoThis() = 0; 5 };
如今咱们须要mock这个抽象类,gmock经过下面的宏来实现:
1 class MockFoo : public FooInterface { 2 public: 3 MockFoo() {} 4 MOCK_METHOD0(DoThis, void()); 5 private: 6 GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFoo); 7 };
MOCK_METHOD*是一个宏,用来mock父类中的虚函数,*表示函数须要接收*个参数。好了,如今有了Mock类,接下来咱们开始写测试用例:
1 class MockFoo : public FooInterface { 2 public: 3 MockFoo() {} 4 MOCK_METHOD0(DoThis, void()); 5 private: 6 GTEST_DISALLOW_COPY_AND_ASSIGN_(MockFoo); 7 };
EXPECT_CALL宏表示将会在后面调用foo对象中的DoThis方法,而且调用次数为1。
一切都准备好了,如今直接make编译运行就能够了,运行结果为:
若是咱们把最后的delete foo去掉会怎么样?
结果就是gmock会报错提示内存泄露了,但须要注意的是若是在函数func里面里面发生了内存泄露,gmock是检查不出来的。
最后若是咱们把Times中预计的DoThis方法运行次数改成2,结果会怎样?
结果这个case运行会失败,预计的次数和实际调用次数不符合。
总结
上面两个demo也只是个简单的示例,它们仅仅展现了gtest和gmock的基本用法,这也是咱们在实际测试时常常须要用到的东西,至于一些高级的功能,须要时能够参考官网文档。