zoukankan      html  css  js  c++  java
  • C++测试利器--google test开源测试框架

    资料

      偶然发现了google的测试框架gtest,马上试了下,效果挺不错,特别是对于写c++的人来说,方便很多。以前自己写c++的模块,通常是写好了模块后再另外定义些函数,然后在函数里面写测试用例来测试模块,如果测试点比较多,光是定义测试函数都要花费不少时间。gtest相当于大大节省了这个过程,用起来非常简单,直接用宏来定义测试用例,并且有很多丰富的宏来辅助测试,例如断言、预测值、死亡测试等。

      废话不多说,先上gtest的一些资料:

    gtest的代码托管地址:https://github.com/google/googletest,用git clone下来就可以了。

    使用gtest构建测试用例指导:https://github.com/google/googletest/tree/master/googletest

    gtest英文文档:https://github.com/google/googletest/blob/master/googletest/docs/Documentation.md

    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的jMockEasyMock

    好了,接下来直接上例子吧(注:下面的例子都是在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的基本用法,这也是我们在实际测试时经常需要用到的东西,至于一些高级的功能,需要时可以参考官网文档。

  • 相关阅读:
    威尔逊置信区间
    mysql函数
    python操作mysql之pymysql
    oracle 表分区
    Python连接sqlserver数据库之pymssql
    python-subprocess
    python-shutil
    python+logging
    公钥加密-DES-RSA
    python-Web-flask-蓝图和单元测试
  • 原文地址:https://www.cnblogs.com/chengxuyuancc/p/6434660.html
Copyright © 2011-2022 走看看