精华内容
下载资源
问答
  • Gtest学习文档

    2018-01-09 08:47:56
    玩转Google开源C++单元测试框架Google Test系列(gtest)(总)
  • gtest 中文文档pdf

    2019-01-09 11:31:20
    google test 中文pdf文档, 你值得拥有!
  • gtest官方文档浅析

    2015-02-11 17:22:00
    gtest的所有官方文档:http://code.google.com/p/googletest/w/list 选择单元测试框架的那些事 gtest不是唯一开源的单元测试框架,我也不觉得它是最好的单元测试框架。 俗话说“杀鸡焉用牛刀”,反过来说我们杀牛...

    gtest的所有官方文档:http://code.google.com/p/googletest/w/list

    选择单元测试框架的那些事

    gtest不是唯一开源的单元测试框架,我也不觉得它是最好的单元测试框架。

    俗话说“杀鸡焉用牛刀”,反过来说我们杀牛的时候也不要用水果刀。在选择单元测试框架这件事情上面,我觉得需要结合被测试的代码一起考虑,“够用”这一点很重要。

    我目前所参与的项目主要偏应用开发,代码里主要体现的是业务的逻辑和流程,相当一部分情况下gtest已经够用了。

    至于不够用的那部分,我们正在尝试采用其他手段来保证代码质量。

    gtest单元测试框架代码、示例代码和官方文档

    “示例丰富,文档清晰”是gtest区别于其他单元测试框架的重要特点。作为新手,如果我们只关注于gtest的使用,而无视SVN上的那些示例代码和官方文档的话,实在可惜。

    gtest官方文档导读

    通过本文开头的链接能够找到gtest所有的官方文档,但真正开始学习的时候,我们是按照gtest版本来看文档的,并不需要全部通吃。

    gtest Test version 1.7文档索引:http://code.google.com/p/googletest/wiki/V1_7_Documentation

    以下是官网文档和对应的中文翻译版本:

    All documentation wiki pages for Google Test

    • Primer -- start here if you are new to Google Test.
    开始使用Google C++ 测试框架
     
     
    • XcodeGuide -- how to use Google Test in Xcode on Mac.
     
     
    To contribute code to Google Test, read
    • DevGuide -- read this before writing your first patch.
     
    • PumpManual -- how we generate some of Google Test's source files.
     

     


    系列文章索引:http://www.cnblogs.com/duxiuxing/p/4270836.html

    转载于:https://www.cnblogs.com/duxiuxing/p/4286645.html

    展开全文
  • gtest是用于单元测试的工具,附件中包含gtest的安装包和使用文档两部分内容
  • GTest

    2019-07-29 18:37:05
    参考链接: https://blog.csdn.net/linhai1028/article/details/81675724 ...一.gtest简介 是Google的一套用于编写C++测试的框架,可以运行在很多平台上(包括Linux、Mac OS X、Windows、Cygwin等等)。基于x...

    参考链接:
    https://blog.csdn.net/linhai1028/article/details/81675724
    https://www.cnblogs.com/helloworldcode/p/9606838.html

    一.gtest简介
    是Google的一套用于编写C++测试的框架,可以运行在很多平台上(包括Linux、Mac OS X、Windows、Cygwin等等)。基于xUnit架构。支持很多好用的特性,包括自动识别测试、丰富的断言、断言自定义、死亡测试、非终止的失败、生成XML报告等等。
    主要用于单元测试.

    二.下载安装

    git clone https://github.com/google/googletest.git
    cd googletest
    cmake ..
    make
    
    sudo cp libgtest*.a  /usr/lib 
    
    sudo cp –a include/gtest /usr/include
    
    
    
    然后在build/lib目录下会生成:libgmock.a  libgmock_main.a  libgtest.a  libgtest_main.a  
    最后我们再 sudo make install
    

    三.gtest之断言 :ASSERT宏 与 EXPECT宏

    1. ASSERT_系列:如果当前点检测失败则退出当前的函数
    2. EXPECT_系列:如果当前点检测失败则继续往下执行
    3. 如果我们对gtest自带的输出不满意的话,可以通过operator<<能够在失败的时候打印日志,将一些自定义的信息输出,如下:
    ASSERT_TRUE(Abs(1) == 1); 
    ASSERT_TRUE(Abs(1) == 1) << "Abs(1)=1";
    
    其中Abs()是自定义的来取绝对值的函数,与<<无关
    

    ASSERT系列的宏:

    bool值检查
    1>、ASSERT_TRUE(参数),期待结果是true
    2>、ASSERT_FALSE(参数),期待结果是false
    数值型数据检查
    3>、ASSERT_EQ(参数1,参数2),传入的是需要比较的两个数  equal
    4>、ASSERT_NE(参数1,参数2),not equal,不等于才返回true
    5>、ASSERT_LT(参数1,参数2),less than,小于才返回true
    6>、ASSERT_GT(参数1,参数2),greater than,大于才返回true
    7>、ASSERT_LE(参数1,参数2),less equal,小于等于才返回true
    8>、ASSERT_GE(参数1,参数2),greater equal,大于等于才返回true
    字符串检查
    9>、ASSERT_STREQ(expected_str, actual_str),两个C风格的字符串相等才正确返回
    10>、ASSERT_STRNE(str1, str2),两个C风格的字符串不相等时才正确返回
    11>、ASSERT_STRCASEEQ(expected_str, actual_str)
    12>、ASSERT_STRCASENE(str1, str2)
    
    
    EXPECT_系列,也是具有类似的宏结构的,如EXPECT_TRUE()
    不同的是,及时遇到失败,还是会继续的向下执行.
    

    使用实例:

      1 #include<iostream>                                                                                                                       
      2 using namespace std;
      3 #include"gtest/gtest.h"
      4 
      5 int Abs(int x)
      6 {
      7     return x > 0 ? x:(x*-1);
      8 }
      9 
     10 // TEST宏有两个参数,第一个是TestSuiteName,第二个是TestCaseName
     11 TEST(IsAbsTest,HandlerTrueReturn)
     12 {
     13         ASSERT_EQ(Abs(1), 1);  //ASSERT_TRUE期待结果是true,operator<<输出一些自定义的信息
     14         ASSERT_TRUE(Abs(-1) == 1) << "Abs(-1)=1";
     15         ASSERT_FALSE(Abs(-2) == -2);  //期待结果是false
     16         ASSERT_EQ(Abs(1),Abs(-1));
     17         ASSERT_NE(Abs(-1),0);
     18         ASSERT_LT(Abs(-1),2);
     19         ASSERT_GT(Abs(-1),0);
     20         ASSERT_LE(Abs(-1),2);
     21         ASSERT_GE(Abs(-1),0);
     22 }
     23 
     24 int main(int argc,char **argv){
     25   testing::InitGoogleTest(&argc,argv);
     26     return RUN_ALL_TESTS();
     27 }
    //需要包括这个主函数,而且主函数的内容是固定不变的
    

    编译

    g++ main.cc -lpthread -lgtest   
    //需要链接线程和gtest库
    
    如果我们不在源文件中写main()函数的话,编译的时候需要链接libgtest_main.a库
    g++ main.cc -lgtest -lgtest_main -lpthread
    

    结果:

    Running main() from /home/txp/mydir/gtest/googletest/googletest/src/gtest_main.cc
    [==========] Running 1 test from 1 test suite.
    [----------] Global test environment set-up.
    [----------] 1 test from IsAbsTest
    [ RUN      ] IsAbsTest.HandlerTrueReturn
    [       OK ] IsAbsTest.HandlerTrueReturn (0 ms)
    [----------] 1 test from IsAbsTest (0 ms total)
    
    [----------] Global test environment tear-down
    [==========] 1 test from 1 test suite ran. (0 ms total)
    [  PASSED  ] 1 test.
    

    四.gtest之事件机制

    事件:框架给我们提供的一个机会,让我们能在这几个机会来执行自己制定的代码买来给测试用例准备/清理数据.

    全局事件
    要实现全局事件,必须写一个类,继承testing::Environment类,实现里面的SetUp和TearDown方法。

    1. SetUp()方法在所有案例执行前执行

    2. TearDown()方法在所有案例执行后执行

    还需要告诉gtest添加这个全局事件,我们需要在main函数中通过testing::AddGlobalTestEnvironment方法将事件挂进来,也就是说,我们可以写很多个这样的类,然后将他们的事件都挂上去。

    TestSuite事件
    我们需要写一个类,继承testing::Test,然后实现两个静态方法

    1. SetUpTestCase() 方法在第一个TestCase之前执行

    2. TearDownTestCase() 方法在最后一个TestCase之后执行

    在编写测试案例时,我们需要使用TEST_F这个宏,第一个参数必须是我们上面类的名字,代表一个TestSuite。

    TestCase事件
    TestCase事件是挂在每个案例执行前后的,实现方式和上面的几乎一样,不过需要实现的是SetUp方法和TearDown方法:

    1. SetUp()方法在每个TestCase之前执行

    2. TearDown()方法在每个TestCase之后执行

    #include<gtest/gtest.h>
    #include<map>
    #include<iostream>
    using namespace std;
    class Student{
    public:
        Student(){
            age=0;
        }
        Student(int a){
            age=a;
        }
        void print(){
        cout<<"*********** "<<age<<" **********"<<endl;;
            }  
    private:
        int age;
    };
    class FooEnvironment : public testing::Environment{
    public:
        virtual void SetUp()
        {
            std::cout << "Foo FooEnvironment SetUP" << std::endl;
        }
        virtual void TearDown()
        {
            std::cout << "Foo FooEnvironment TearDown" << std::endl;
        }
    };
    static Student *s;
    //在第一个test之前,最后一个test之后调用SetUpTestCase()和TearDownTestCase()
    class TestMap:public testing::Test
    {
    public:
        static void SetUpTestCase()
        {
            cout<<"SetUpTestCase()"<<endl;
        s=new Student(23);
        }
     
        static void TearDownTestCase()
        {
        delete s;
            cout<<"TearDownTestCase()"<<endl;
        }
        void SetUp()
        {
            cout<<"SetUp() is running"<<endl;
             
        }
        void TearDown()
        {
            cout<<"TearDown()"<<endl;
        } 
    };
     
    TEST_F(TestMap, Test1)
     {
     
        // you can refer to s here
        s->print();
    }
    int main(int argc, char** argv)
    {
        testing::AddGlobalTestEnvironment(new FooEnvironment);
        testing::InitGoogleTest(&argc, argv);
        return RUN_ALL_TESTS();
    }
    

    在这里插入图片描述
    五.gtest之死亡测试

    ”死亡”指的是程序的奔溃。通常在测试的过程中,我们需要考虑各种各样的输入,有的输入可能直接导致程序奔溃,这个时候我们就要检查程序是否按照预期的方式挂掉,这也就是所谓的”死亡测试”。

    1>、ASSERT_DEATH(参数1,参数2)
    程序挂了并且错误信息和参数2匹配,此时认为测试通过。如果参数2为空字符串,则只需要看程序挂没挂即可。
    
    2>、ASSERT_EXIT(参数1,参数2,参数3)
    语句停止并且错误信息和被提前给的信息匹配。
    
    #include<gtest/gtest.h>
    int func() //访问空指针
    {
    	int *p=NULL;
    	*ptr = 100;
    	return 0;
    }
    
    TEST (FuncDeathTest,Nullptr)
    {
    	ASSERT_DEATH(func()," ");
    }
    

    六.gtest之参数测试

    当考虑多次要为被测函数传入不同的值的情况时,可以按下面的方式去测试。必须添加一个类,继承testing::TestWithParam。其中T就是你需要参数化的参数类型,如下面的案例是int型参数。(官方文档上的案例)

    #include<gtest/gtest.h>
    // Returns true iff n is a prime number.
    bool IsPrime(int n)
    {
        // Trivial case 1: small numbers
        if (n <= 1) return false;
        // Trivial case 2: even numbers
        if (n % 2 == 0) return n == 2;
        // Now, we have that n is odd and n >= 3.
        // Try to divide n by every odd number i, starting from 3
        for (int i = 3; ; i += 2) {
            // We only have to try i up to the squre root of n
            if (i > n/i) break;
            // Now, we have i <= n/i < n.
            // If n is divisible by i, n is not prime.
            if (n % i == 0) return false;
        }
        // n has no integer factor in the range (1, n), and thus is prime.
        return true;
    }
    class IsPrimeParamTest : public::testing::TestWithParam<int>{};
    TEST_P(IsPrimeParamTest, HandleTrueReturn)
    {
     int n =  GetParam();
     EXPECT_TRUE(IsPrime(n));
    }
    //被测函数须传入多个相关的值
    INSTANTIATE_TEST_CASE_P(TrueReturn, IsPrimeParamTest, testing::Values(3, 5, 11, 23, 17));
    int main(int argc, char **argv)
    {
        testing::InitGoogleTest(&argc, argv);
        return RUN_ALL_TESTS();
    }
    

    七.一个关于gtest的例子

    #include<iostream>
    using namespace std;
    #include<gtest/gtest.h>
    
    struct LinkNode
    {
        int _data;
        LinkNode *_next;
        LinkNode(const int& data)
            :_data(data)
            ,_next(NULL)
        {}
    };
    
    class Link
    {
    public:
        Link()
            :pHead(new LinkNode(0))
        {}
        void PushBack(const int& data)
        {
            if(pHead == NULL)
                return ;
            LinkNode *newNode=new LinkNode(data);
            if(pHead->_next == NULL){  //第一次插入结点
                pHead->_next=newNode;
            }
            else{  //找到最后一个结点直接尾插
                LinkNode *cur=pHead->_next;
                while(cur->_next){
                    cur=cur->_next;
                }
                cur->_next=newNode;
            }
        }
    
        void PopBack()
        {
            if(pHead == NULL)
                return ;
            LinkNode *cur=pHead;
            LinkNode *prev=NULL;
            while(cur->_next)
            {
                prev=cur;
                cur=cur->_next;
            }
            prev->_next=NULL;
            delete cur;
        }
    
        LinkNode *FindNode(const int& data)
        {
            if(pHead == NULL)
                return NULL;
            LinkNode *cur=pHead->_next;
            while(cur)
            {
                if(cur->_data == data)
                    return cur;
                cur=cur->_next;
            }
            return NULL;
        }
    
        bool Delete(int data)
        {
            LinkNode *pos=FindNode(data);
            if(pos == NULL)
                return false;
            LinkNode *cur=pHead->_next;
            while(cur->_next != pos)
            {
                cur=cur->_next;
            }
            cur->_next=pos->_next;
            delete pos;
            return true;
        }
    
        void Destroy()
        {
            if(pHead == NULL)
                return;
            LinkNode *cur=pHead->_next;
            while(cur)
            {
                LinkNode *del=cur;
                cur=cur->_next;
                delete del;
                del=NULL;
            }
            delete pHead;  //删除头结点
        }
        LinkNode *pHead;
    };
    
    class TestLink:public testing::Test
    {
    public:
        virtual void SetUp()
        {
            cout<<"SetUp"<<endl;
            for(int i=1;i<=5;i++){
                link.PushBack(i);
            }
        }
        virtual void TearDown()
        {
            cout<<"TearDown"<<endl;
            link.Destroy();
        }
        Link link;
    };
    
    TEST_F(TestLink,PushBack)
    {
        ASSERT_FALSE(link.pHead == NULL);
        link.PushBack(9);
        LinkNode *res=link.FindNode(9);
        ASSERT_FALSE(res == NULL);
    }
    
    TEST_F(TestLink,PopBack)
    {
        for(int i=1;i<=5;i++){
            link.PopBack();
        }
    }
    
    TEST_F(TestLink,FindNode)
    {
        ASSERT_TRUE(link.FindNode(3));
        ASSERT_TRUE(link.FindNode(2));
        ASSERT_TRUE(link.FindNode(4));
        ASSERT_TRUE(link.FindNode(5));
        ASSERT_TRUE(link.FindNode(1));
        ASSERT_FALSE(link.FindNode(7));
    }
    
    TEST_F(TestLink,Delete)
    {
        ASSERT_FALSE(link.pHead == NULL);
        ASSERT_TRUE(link.Delete(3) == true);
        ASSERT_TRUE(link.Delete(9) == false);
    }
    
    int main(int argc,char *argv[])
    {
        testing::InitGoogleTest(&argc,argv);
        return RUN_ALL_TESTS();
    }
    
    展开全文
  • gtest框架使用

    千次阅读 2013-07-31 18:40:10
    gtest文档说明:   由于公司单元测试的需要,自己花了大半天时间下载了一个gtest框架,使用了一些测试例子,总览了coderzh的玩转gtest测试框架,又看了几篇gtest博客,写下了以下内容,作为备忘。毕竟我需要的简单...

    gtest文档说明:
     

    由于公司单元测试的需要,自己花了大半天时间下载了一个gtest框架,使用了一些测试例子,总览了coderzh的玩转gtest测试框架,又看了几篇gtest博客,写下了以下内容,作为备忘。毕竟我需要的简单的东西,太复杂了我自己很难回顾起来。在此很感谢coderzh,他的玩转google开源框架gtest系列的文章真的不错,极力推荐。链接地址:http://www.cnblogs.com/coderzh/archive/2009/04/06/1426755.html,这篇文件就比较深入了一些,适合深入研究的人看。

     

    工程项目简介与基本配置:

    1,改造了一下gtest的目录结构,与我们平常使用的工程目录接口相匹配
    2,使用gtest库,需要头文件位于include\gtest目录下,需要lib文件位于lib\gtestd.lib。
    3,注意工程配置需要配置成多线程调试模式,即MTd模式。vs20080->属性->配置属性->代码生成->运行时库->多线程调试(/MTd)
    4,工程需要包含头文件include\gtest\gtest.h,需要包含库目录lib\gtestd.lib。


    //-----------------------------------------------------------------------------

    比较测试:

    //基本代码框架
    TEST(TestSuitEqualTest, TestCase1)
    {
    EXPECT_EQ(1, min(1,2));//可以通过
    }

    1,数值型比较:

    EXPECT_EQ(1, min(1,2));//可以通过
    EXPECT_EQ(1, min(10,2));//不可以通过


    EXPECT_EQ传递的两个参数左边是期待的值,右边是自己的函数,即要测试的函数。
    比较还有有一系列的函数如下:
    //    * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
    //    * {ASSERT|EXPECT}_NE(v1, v2):           Tests that v1 != v2
    //    * {ASSERT|EXPECT}_LT(v1, v2):           Tests that v1 < v2
    //    * {ASSERT|EXPECT}_LE(v1, v2):           Tests that v1 <= v2
    //    * {ASSERT|EXPECT}_GT(v1, v2):           Tests that v1 > v2
    //    * {ASSERT|EXPECT}_GE(v1, v2):           Tests that v1 >= v2
    断言assert与expect的区别是expect出现失败会在当前函数中继续运行下去,assert失败后退出当前函数,但是并不会退出整个程序。

    2,bool值比较

    //true false比较

    EXPECT_TRUE(true);//可以通过
    EXPECT_FALSE(true);//不可以通过

    对于这种true,false测试可以打印传入的参数。

    EXPECT_PRED2(MutuallyPrime, m, n);//yes


    3,字符串比较
    //字符串 不区分大小写比较

    EXPECT_STRCASEEQ("how", "how");//yes
    EXPECT_STRCASEEQ("how", "HOW");//yes
    EXPECT_STRCASEEQ("how", "how are");//no


    //字符串 区分大小写比较

    EXPECT_STREQ("how", "how");//yes
    EXPECT_STREQ("how", "HOW");//no
    EXPECT_STREQ("how", "how are");//no

    4,案例失败时候能够精确定位问题所在

    int n = -1;  
    bool actualResult = Foo::Dosometing(n);  
    ASSERT_TRUE(actualResult) << "Call Foo::Dosometing(n) when n = " << n;

     


    //-----------------------------------------------------------------------------

     

    事件机制:

    gtest提供了多种事件机制,以便在案例执行之前准备测试数据和测试之后释放相关资源。gtest的事件一共有3种:
    全局的,所有案例执行前后(继承testing::Environment类,实现里面的SetUp和TearDown方法 )
    TestSuite级别的,在某一批案例中第一个案例前,最后一个案例执行后(继承testing::Test类,实现里面的SetUpTestCase和TearDownTestCase静态方法
    TestCase级别的,每个TestCase前后(继承testing::Test类,实现里面的SetUp和TearDown方法 )
    全局级别的:
    //全局事件

     

     

    class FooEnvironment : public testing::Environment
    {
    public:
    	virtual void SetUp()
    	{
    		std::cout << "Foo FooEnvironment SetUP" << std::endl;
    	}
    	virtual void TearDown()
    	{
    		std::cout << "Foo FooEnvironment TearDown" << std::endl;
    	}
    };



    在main函数中添加:

     

    testing::AddGlobalTestEnvironment(new FooEnvironment());

     

    	
    class FooTest : public testing::Test
    {
    protected:
        static void SetUpTestCase(){ cout << "SetUpTestCase" << endl;}
        static void TearDownTestCase(){ cout << "TearDownTestCase" << endl;}
        static int m_nShareAllCaseInt;//此变量为一个testsuit的所有case公有
    protected:
        virtual void SetUp(){ cout << "SetUp" << endl;}
        virtual void TearDown(){ cout << "TearDown" << endl;}   
        int m_nCaseInt;//此变量为每一个case自己所有
    };
    int FooTest::m_nShareAllCaseInt=100;



    //仔细分析c++的静态成员变量和普通成员变量就明白了,m_nShareAllCaseInt为类的成员变量,为公有;m_nCaseInt为对象成员变量,每一个对象自己所有
    //TEST_F实际上是创建了一个类继承于FooTest,同时创建了此类的对象。因此下面两个TEST_F公有一个静态成员变量,各自私有m_nCaseInt

     

    TEST_F(FooTest, Test0){ cout << "Test0" << endl;}
    TEST_F(FooTest, Test1){ cout << "Test1" << endl;}


    //-----------------------------------------------------------------------------

     

    //批量参数测试

     

    class ParamTest : public::testing::TestWithParam<int>
    {
    };
    TEST_P(ParamTest, aLotTest)
    {
    	int n = GetParam();
    	int m = GetParam();
    	cout<<"m="<<m<<" n="<<n<<endl;
    	EXPECT_TRUE(m == n);
    }
    INSTANTIATE_TEST_CASE_P(EqualParamTest, ParamTest, testing::Values(1, 10, 100, 1000, 10000));//参数生成器


    //批量化测试:

     

    INSTANTIATE_TEST_CASE_P(PreName, myTest, testing::Values(1, 10, 100, 1000, 10000));

    第一个参数是测试结束时进行打印的一系列测试案例的前缀,无限制。 
    第二个参数是测试case的名称,需要和之前定义的参数化的类的名称相同,在这个例子里是myTest.
    第三个参数就是参数生成器。除了上面的例子所使用的test::Values,gtest还提供了一系列的参数生成的函数:
    Range(begin, end[, step]) 范围在begin~end之间,步长为step,不包括end
    Values(v1, v2, ..., vN) v1,v2到vN的值
    ValuesIn(container) and ValuesIn(begin, end) 从一个C类型的数组或是STL容器,或是迭代器中取值
    Bool() 取false 和 true 两个值 
    Combine(g1, g2, ..., gN) 这个比较强悍,它将g1,g2,...gN进行排列组合,g1,g2,...gN本身是一系列参数生成器,每次分别从g1,g2,..gN中各取出一个值,组合成一个元组(Tuple)作为一个参数。


    //-----------------------------------------------------------------------------

     

    //简单白盒测试例子

     

    class Foo//待测试类
    {public:
    	Foo(void): sum(0){}
    	void add(int num){ sum += num;}
    	void print(){ std::cout << sum << std::endl;}
    	friend class unittest_Foo;//声明友类
    private:
    	int sum;//私有变量
    };
    class unittest_Foo : public testing::Test		
    {public:
    	static void test_foo()	{//可以任意访问A的私有变量和私有函数
    		Foo a;	ASSERT_EQ(a.sum, 0);
    		a.add(0); ASSERT_EQ(a.sum, 0);
    		a.add(100); ASSERT_EQ(a.sum, 100);}
    };
    TEST_F(unittest_Foo, test_foo){	unittest_Foo::test_foo();}

     


    //-----------------------------------------------------------------------------

     

     

    //运行参数:

    gtest提供多种方式来设置运行参数。其中使用命令行参数最为常用。


    --gtest_filter :对执行的测试案例进行过滤,支持通配符
    ?    单个字符
    *    任意字符
    -    排除,如,-a 表示除了a
    :    取或,如,a:b 表示a或b
    比如下面的例子:
    ./foo_test 没有指定过滤条件,运行所有案例
    ./foo_test --gtest_filter=*   使用通配符,同样运行所有案例
    ./foo_test --gtest_filter=Foo.* 运行Foo案例集下所有案例
    ./foo_test --gtest_filter=Foo.test 运行案例Foo.test


    --gtest_repeat :执行若干次
    ./foo_test -- gtest_repeat=5 重复执行5次

     

    展开全文
  • gtest

    2019-09-15 15:46:20
    #include <iostream> using namespace std; ////////////////////////////////////////////////////////////////////////// // 简单示例 int ...

    #include <iostream>

    using namespace std;

    //
    // 简单示例
    int Foo(int a, int b)
    {
        if (a == 0 || b == 0)
        {
            throw "don't do that";
        }

        int c = a % b;

        if (c == 0)
        {
            return b;
        }

        return Foo(b, c);
    }

    //
    TEST(ABC, ABC1)
    {
        // ASSERT_EQ(expected, actual);
        // ASSERT_TRUE(condition);
        // ASSERT_STREQ(expected_str, actual_str);
        // ASSERT_FLOAT_EQ(expected, actual);
        // ASSERT_DOUBLE_EQ(expected, actual);

        // ASSERT_NEAR(val1, val2, abs_error);

        // ASSERT_NE

        // ASSERT_GT

        // ASSERT_LT

        // ASSERT_GE

        // ASSERT_LE

        // ASSERT_STREQ

        // ASSERT_STRNE

        // ASSERT_STRCASEEQ

        // ASSERT_STRCASENE

        // ASSERT_PRED1


        ASSERT_TRUE(1); // assert可以用expect代替,assert失败时程序停止执行,expect失败时程序继续执行
        ASSERT_FALSE(1);
    }

    // 添加一个测试,第一个参数google称为test case name(在XUnit中叫suite),第二个参数为test name(在XUnit中叫test case)
    TEST(FooTestSuite, FooTestCase1)
    {
        EXPECT_EQ(2, Foo(4, 10));
        EXPECT_EQ(6, Foo(30, 18));
    }

    //
    // predicate
    bool FooABC(int m, int n)
    {
        return Foo(m, n) > 1;
    }

    TEST(PredicateAssertionTestSuite, TestCase1)
    {
        int m = 5, n = 6;
        EXPECT_EQ(1, Foo(5, 6));
        EXPECT_PRED2(FooABC, m, n); // FooABC(m, n)返回true时通过测试,否则不通过。2表示有2个参数
    }

    //
    // predicate,失败时按自己的格式输出错误信息,注意函数的声明
    testing::AssertionResult AssertFoo(const char* m_expr, const char* n_expr, const char* k_expr,
                                       int m, int n, int k)
    {
        if (Foo(m, n) == k)
        {
            return testing::AssertionSuccess();
        }

        testing::Message msg;
        msg << m_expr << " 和 " << n_expr << " 的最大公约数应该是:" << Foo(m, n) << " 而不是:" << k_expr;
        return testing::AssertionFailure(msg);
    }

    TEST(AssertFooTestSuite, TestCase1)
    {
        EXPECT_PRED_FORMAT3(AssertFoo, 3, 6, 2); // 3表示有3个参数
    }

    //
    // 类型检查,类型不是期待的则编译不通过
    template<typename T>
    class StaticAssertTypeEqTestHelper
    {
    public:
        StaticAssertTypeEqTestHelper()
        {
            testing::StaticAssertTypeEq<bool, T>();
        }
    };

    TEST(StaticAssertTypeEqTest, WorksInClass)
    {
        StaticAssertTypeEqTestHelper<bool>();
    }

    //

    // 全局事件,继承testing::Environment类,是所有测试用例共用的全局环境。需要在main函数中调用AddGlobalTestEnvironment注册,可以写很多个这样的类,然后将它们都注册上去。

    // 当需要在所有的测试间共享一个相同的环境来保存和传递状态,或者环境的状态是只读的,可以只初始化一次,或者创建环境的开销很大,要求只初始化一次等

    class GlobalEnv : public testing::Environment
    {
    public:
        virtual void SetUp()
        {
            cout << "all begin" << endl; // 该函数在执行全部的测试用例(所有的suite)之前执行
        }

        virtual void TearDown()
        {
            cout << "all end" << endl; // 该函数在执行全部的测试用例之后执行
        }
    };


    int main(int argc, char* argv[])
    {
        testing::AddGlobalTestEnvironment(new GlobalEnv());
        testing::InitGoogleTest(&argc, argv);
        return RUN_ALL_TESTS();
    }

    //
    class SharedRes
    {
    private:
        int i;
    };

    // 继承自testing::Test
    class FooTest : public testing::Test
    {
    protected:
        // Some expensive resource shared by all tests.
        static SharedRes* shared_res;

        static void SetUpTestCase() // 静态方法,在一组测试用例(suite,即本类中定义的测试用例)前执行。当需要在本类的各个测试间共享一个相同的环境来保存和传递状态,或者环境的状态是只读的,可以只初始化一次,或者创建环境的开销很大,要求只初始化一次等。注意是静态的。
        {
            shared_res = new SharedRes();

            cout << "test suite begin" << endl;
        }

        static void TearDownTestCase() // 静态方法,在一组测试用例(suite,即本类中定义的测试用例)后执行
        {
            delete shared_res;
            shared_res = NULL;

            cout << "test suite end" << endl;
        }
    };

    SharedRes* FooTest::shared_res = 0;

    // 需要使用TEST_F宏,第一个参数必须是上面Test的子类名(表示同一个suite)。F是fixture的意思,TEST_F又从用户定义的类自动派生了一个类,因此要求public或protected的访问权限
    TEST_F(FooTest, FooTest1)
    {
        // you can refer to shared_res here
        // 可以访问FooTest类的非私有成员
        EXPECT_EQ(1, 1);
        EXPECT_NE(1, 2);
    }

    TEST_F(FooTest, FooTest2)
    {
        // you can refer to shared_res here
        EXPECT_LT(1, 2);
        EXPECT_GT(1, 2);
        EXPECT_LE(1, 2);
        EXPECT_GE(1, 2);
    }

    //
    class Bar
    {
    public:
        int Init()
        {
            return 0;
        }

        int Finalize()
        {
            return 0;
        }

        int Do(int m, int n)
        {
            return m - n;
        }
    };

    // 继承自testing::Test
    class BarTest : public testing::Test // 同样是Test的子类
    {
    protected:
        Bar bar;

        virtual void SetUp() // 在每个test之前执行
        {
            bar.Init();

            cout << "test case begin" << endl;
        }

        virtual void TearDown() // 在每个test之后执行
        {
            bar.Finalize();

            cout << "test case end" << endl;

        }


        int Foo()

        {
            int i;
            for (i = 0; i < 100; ++i)
            {
                ;
            }

            return 0;
        }

    };

    // 需要使用TEST_F宏,第一个参数必须是上面的类名(Test的子类)
    TEST_F(BarTest, BarTest1)
    {
        // 可以访问BarTest类的成员
        EXPECT_EQ(4, bar.Do(12, 16));
    }

    TEST_F(BarTest, BarTest2)
    {

        EXPECT_EQ(0, Foo()); // 直接调用类的成员函数

    }

    //
    // 值参数化测试(Value Parameterized Test)
    // Returns true iff n is a prime number.
    bool IsPrime(int n)
    {
        // Trivial case 1: small numbers
        if (n <= 1)
            return false;

        // Trivial case 2: even numbers
        if (n % 2 == 0)
            return n == 2;

        // Now, we have that n is odd and n >= 3.

        // Try to divide n by every odd number i, starting from 3
        for (int i = 3;; i += 2)
        {
            // We only have to try i up to the squre root of n
            if (i > n / i)
                break;

            // Now, we have i <= n/i < n.
            // If n is divisible by i, n is not prime.
            if (n % i == 0)
                return false;
        }
        // n has no integer factor in the range (1, n), and thus is prime.
        return true;
    }

    // 需要添加一个类,继承testing::TestWithParam<T>,其中T就是需要参数化的参数类型
    class IsPrimeParamTest : public ::testing::TestWithParam<int>
    {

    };

    // 需要使用TEST_P宏,第一个参数是上面TestWithParam的子类名,在TEST_P宏里,使用GetParam()获取当前的参数的具体值
    TEST_P(IsPrimeParamTest, HandleTrueReturn)
    {
        int n = GetParam();
        EXPECT_TRUE(IsPrime(n));
    }

    // 设置参数列表,第一个参数是前缀名,随便取,第二个参数是上面TestWithParam的子类名,第三个参数是测试参数列表
    INSTANTIATE_TEST_CASE_P(TrueReturn, IsPrimeParamTest, testing::Values(3, 5, 11, 23, 17));// 类似的函数有Range(begin, end[, step])等

    //
    int main(int argc, char* argv[])
    {
        testing::AddGlobalTestEnvironment(new GlobalEnv); // 添加一个全局事件,可以添加多个

        testing::InitGoogleTest(&argc, argv);
        return RUN_ALL_TESTS();
    }

    //

    // 异常测试

    ASSERT_NO_THROW

    ASSERT_ANY_THROW

    ASSERT_THROW


    //

    // 直接返回成功或失败
    TEST(ExplicitTest, Demo)
    {
        ADD_FAILURE() << "Sorry"; // None Fatal Asserton,继续往下执行。
        //FAIL(); // Fatal Assertion,不往下执行该案例。
        SUCCEED();
    }


    五、类型参数化 

    gtest还提供了应付各种不同类型的数据时的方案,以及参数化类型的方案。我个人感觉这个方案有些复杂。首先要了解一下类型化测试,就用gtest里的例子了。

    首先定义一个模版类,继承testing::Test

    template <typename T>
    class FooTest : public testing::Test {
     
    public:
      

      typedef std::list<T> List;
      static T shared_;
      T value_;
    };

     

    接着我们定义需要测试到的具体数据类型,比如下面定义了需要测试char,int和unsigned int :

    typedef testing::Types<charint, unsigned int> MyTypes;
    TYPED_TEST_CASE(FooTest, MyTypes);

     

    又是一个新的宏,来完成我们的测试案例,在声明模版的数据类型时,使用TypeParam 

    TYPED_TEST(FooTest, DoesBlah) {
      
    // Inside a test, refer to the special name TypeParam to get the type
      // parameter.  Since we are inside a derived class template, C++ requires
      // us to visit the members of FooTest via 'this'.
      TypeParam n = this->value_;

      
    // To visit static members of the fixture, add the 'TestFixture::'
      // prefix.
      n += TestFixture::shared_;

      
    // To refer to typedefs in the fixture, add the 'typename TestFixture::'
      // prefix.  The 'typename' is required to satisfy the compiler.
      typename TestFixture::List values;
      values.push_back(n);
      

    }

    上面的例子看上去也像是类型的参数化,但是还不够灵活,因为需要事先知道类型的列表。gtest还提供一种更加灵活的类型参数化的方式,允许你在完成测试的逻辑代码之后再去考虑需要参数化的类型列表,并且还可以重复的使用这个类型列表。下面也是官方的例子:

    template <typename T>
    class FooTest : public testing::Test {
      

    };

    TYPED_TEST_CASE_P(FooTest);

     

    接着又是一个新的宏TYPED_TEST_P类完成我们的测试案例:

    TYPED_TEST_P(FooTest, DoesBlah) {
      
    // Inside a test, refer to TypeParam to get the type parameter.
      TypeParam n = 0;
      

    }

    TYPED_TEST_P(FooTest, HasPropertyA) {  }

    接着,我们需要我们上面的案例,使用REGISTER_TYPED_TEST_CASE_P宏,第一个参数是testcase的名称,后面的参数是test的名称

    REGISTER_TYPED_TEST_CASE_P(FooTest, DoesBlah, HasPropertyA);

    接着指定需要的类型列表:

    typedef testing::Types<charint, unsigned int> MyTypes;
    INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);

    这种方案相比之前的方案提供更加好的灵活度,当然,框架越灵活,复杂度也会随之增加。 

     

     

     

    一、前言

    “死亡测试”名字比较恐怖,这里的“死亡”指的的是程序的崩溃。通常在测试过程中,我们需要考虑各种各样的输入,有的输入可能直接导致程序崩溃,这时我们就需要检查程序是否按照预期的方式挂掉,这也就是所谓的“死亡测试”。gtest的死亡测试能做到在一个安全的环境下执行崩溃的测试案例,同时又对崩溃结果进行验证。

    二、使用的宏

    Fatal assertion

    Nonfatal assertion

    Verifies

    ASSERT_DEATH(statement, regex`);

    EXPECT_DEATH(statement, regex`);

    statement crashes with the given error

    ASSERT_EXIT(statement, predicate, regex`);

    EXPECT_EXIT(statement, predicate, regex`);

    statement exits with the given error and its exit code matches predicate

     

    由于有些异常只在Debug下抛出,因此还提供了*_DEBUG_DEATH,用来处理Debug和Realease下的不同。

    三、*_DEATH(statement,regex`)

    1. statement是被测试的代码语句

    2. regex是一个正则表达式,用来匹配异常时在stderr中输出的内容

    如下面的例子: 

    void Foo()
    {
        
    int *pInt = 0;
        *pInt = 
    42 ;
    }

    TEST(FooDeathTest, Demo)
    {
        EXPECT_DEATH(Foo(), 
    "");
    }

     

    重要:编写死亡测试案例时,TEST的第一个参数,即testcase_name,请使用DeathTest后缀。原因是gtest会优先运行死亡测试案例,应该是为线程安全考虑。

    四、*_EXIT(statement, predicate,regex`)

    1. statement是被测试的代码语句

    2. predicate 在这里必须是一个委托,接收int型参数,并返回bool。只有当返回值为true时,死亡测试案例才算通过。gtest提供了一些常用的predicate:

    testing::ExitedWithCode(exit_code)


    如果程序正常退出并且退出码与exit_code相同则返回 true

    testing::KilledBySignal(signal_number)  // Windows下不支持

     
    如果程序被signal_number信号kill的话就返回true

    3. regex是一个正则表达式,用来匹配异常时在stderr中输出的内容

    这里, 要说明的是,*_DEATH其实是对*_EXIT进行的一次包装,*_DEATH的predicate判断进程是否以非0退出码退出或被一个信号杀死。

    例子:

    TEST(ExitDeathTest, Demo)
    {
        EXPECT_EXIT(_exit(
    1),  testing::ExitedWithCode(1),  "");
    }

     

    五、*_DEBUG_DEATH

    先来看定义:

    #ifdef NDEBUG

    #define EXPECT_DEBUG_DEATH(statement, regex) \
      
    do { statement; } while (false)

    #define ASSERT_DEBUG_DEATH(statement, regex) \
      
    do { statement; } while (false)

    #else

    #define EXPECT_DEBUG_DEATH(statement, regex) \
      EXPECT_DEATH(statement, regex)

    #define ASSERT_DEBUG_DEATH(statement, regex) \
      ASSERT_DEATH(statement, regex)

    #endif  // NDEBUG for EXPECT_DEBUG_DEATH

     

    可以看到,在Debug版和Release版本下, *_DEBUG_DEATH的定义不一样。因为很多异常只会在Debug版本下抛出,而在Realease版本下不会抛出,所以针对Debug和Release分别做了不同的处理。看gtest里自带的例子就明白了:

    int DieInDebugElse12(int* sideeffect) {
        
    if (sideeffect) *sideeffect = 12;
    #ifndef NDEBUG
        GTEST_LOG_(FATAL, 
    "debug death inside DieInDebugElse12()");
    #endif  // NDEBUG
        
    return 12;
    }

    TEST(TestCase, TestDieOr12WorksInDgbAndOpt)
    {
        
    int sideeffect = 0;
        
    // Only asserts in dbg.
        EXPECT_DEBUG_DEATH(DieInDebugElse12(&sideeffect), "death");

        #ifdef NDEBUG
        
    // opt-mode has sideeffect visible.
        EXPECT_EQ(12, sideeffect);
        
    #else
        
    // dbg-mode no visible sideeffect.
        EXPECT_EQ(0, sideeffect);
        
    #endif
    }

     

    六、关于正则表达式

    POSIX系统(Linux, Cygwin, 和 Mac)中,gtest的死亡测试中使用的是POSIX风格的正则表达式,想了解POSIX风格表达式可参考: 

    1. POSIX extended regularexpression

    2. Wikipedia entry.

    在Windows系统中,gtest的死亡测试中使用的是gtest自己实现的简单的正则表达式语法。 相比POSIX风格,gtest的简单正则表达式少了很多内容,比如 ("x|y"),("(xy)"),("[xy]") ("x{5,7}")都不支持。

    下面是简单正则表达式支持的一些内容:

    matches any literal character c

    \\d

    matches any decimal digit

    \\D

    matches any character that's not a decimal digit

    \\f

    matches \f

    \\n

    matches \n

    \\r

    matches \r

    \\s

    matches any ASCII whitespace, including \n

    \\S

    matches any character that's not a whitespace

    \\t

    matches \t

    \\v

    matches \v

    \\w

    matches any letter, _, or decimal digit

    \\W

    matches any character that \\w doesn't match

    \\c

    matches any literal character c, which must be a punctuation

    .

    matches any single character except \n

    A?

    matches 0 or 1 occurrences of A

    A*

    matches 0 or many occurrences of A

    A+

    matches 1 or many occurrences of A

    ^

    matches the beginning of a string (not that of each line)

    $

    matches the end of a string (not that of each line)

    xy

    matches x followed by y

     

    gtest定义两个宏,用来表示当前系统支持哪套正则表达式风格:

    1. POSIX风格:GTEST_USES_POSIX_RE = 1 

    2. Simple风格:GTEST_USES_SIMPLE_RE=1

    七、死亡测试运行方式

    1. fast方式(默认的方式)

    testing::FLAGS_gtest_death_test_style = "fast";

    2. threadsafe方式

    testing::FLAGS_gtest_death_test_style = "threadsafe";

     

    你可以在 main() 里为所有的死亡测试设置测试形式,也可以为某次测试单独设置。Google Test会在每次测试之前保存这个标记并在测试完成后恢复,所以你不需要去管这部分工作 。如:

    TEST(MyDeathTest, TestOne) {
      testing::FLAGS_gtest_death_test_style = 
    "threadsafe";
      
    // This test is run in the "threadsafe" style:
      ASSERT_DEATH(ThisShouldDie(), "");
    }

    TEST(MyDeathTest, TestTwo) {
      
    // This test is run in the "fast" style:
      ASSERT_DEATH(ThisShouldDie(), "");
    }

    int main(int argc, char** argv) {
      testing::InitGoogleTest(&argc, argv);
      testing::FLAGS_gtest_death_test_style = 
    "fast";
      
    return RUN_ALL_TESTS();
    }

     

    八、注意事项

    1. 不要在死亡测试里释放内存。

    2. 在父进程里再次释放内存。

    3. 不要在程序中使用内存堆检查。

    九、总结

    关于死亡测试,gtest官方的文档已经很详细了,同时在源码中也有大量的示例。如想了解更多的请参考官方的文档,或是直接看gtest源码。

    简单来说,通过*_DEATH(statement, regex`)和*_EXIT(statement, predicate, regex`),我们可以非常方便的编写导致崩溃的测试案例,并且在不影响其他案例执行的情况下,对崩溃案例的结果进行检查。

     

     

     

    ///

     

    一、前言

    使用gtest编写的测试案例通常本身就是一个可执行文件,因此运行起来非常方便。同时,gtest也为我们提供了一系列的运行参数(环境变量、命令行参数或代码里指定),使得我们可以对案例的执行进行一些有效的控制。

    二、基本介绍

    前面提到,对于运行参数,gtest提供了三种设置的途径:

    1. 系统环境变量

    2. 命令行参数

    3. 代码中指定FLAG

    因为提供了三种途径,就会有优先级的问题, 有一个原则是,最后设置的那个会生效。不过总结一下,通常情况下,比较理想的优先级为:

    命令行参数 > 代码中指定FLAG> 系统环境变量

    为什么我们编写的测试案例能够处理这些命令行参数呢?是因为我们在main函数中,将命令行参数交给了gtest,由gtest来搞定命令行参数的问题。

    int _tmain(int argc, _TCHAR* argv[])
    {
        testing::InitGoogleTest(&argc, argv);
        
    return RUN_ALL_TESTS();
    }

     

    这样,我们就拥有了接收和响应gtest命令行参数的能力。如果需要在代码中指定FLAG,可以使用testing::GTEST_FLAG这个宏来设置。比如相对于命令行参数--gtest_output,可以使用testing::GTEST_FLAG(output)= "xml:";来设置。注意到了,不需要加--gtest前缀了。同时,推荐将这句放置InitGoogleTest之前,这样就可以使得对于同样的参数,命令行参数优先级高于代码中指定。

    int _tmain(int argc, _TCHAR* argv[])
    {
        testing::GTEST_FLAG(output) = 
    "xml:";
        testing::InitGoogleTest(&argc, argv);
        
    return RUN_ALL_TESTS();
    }

     

    最后再来说下第一种设置方式-系统环境变量。如果需要gtest的设置系统环境变量,必须注意的是:

    1. 系统环境变量全大写,比如对于--gtest_output,响应的系统环境变量为:GTEST_OUTPUT

    2.  有一个命令行参数例外,那就是--gtest_list_tests,它是不接受系统环境变量的。(只是用来罗列测试案例名称)

    三、参数列表

    了解了上面的内容,我这里就直接将所有命令行参数总结和罗列一下。如果想要获得详细的命令行说明,直接运行你的案例,输入命令行参数:/? 或 --help 或 -help

    1. 测试案例集合

    命令行参数

    说明

    --gtest_list_tests

    使用这个参数时,将不会执行里面的测试案例,而是输出一个案例的列表。

    --gtest_filter

    对执行的测试案例进行过滤,支持通配符

    ?    单个字符

    *    任意字符

    -    排除,如,-a 表示除了a

    :    取或,如,a:b 表示a或b

    比如下面的例子:

    ./foo_test 没有指定过滤条件,运行所有案例
    ./foo_test --gtest_filter=* 使用通配符*,表示运行所有案例
    ./foo_test --gtest_filter=FooTest.* 运行所有“测试案例名称(testcase_name)”为FooTest的案例
    ./foo_test --gtest_filter=*Null*:*Constructor* 运行所有“测试案例名称(testcase_name)”或“测试名称(test_name)”包含Null或Constructor的案例。
    ./foo_test --gtest_filter=-*DeathTest.* 运行所有非死亡测试案例。
    ./foo_test --gtest_filter=FooTest.*-FooTest.Bar 运行所有“测试案例名称(testcase_name)”为FooTest的案例,但是除了FooTest.Bar这个案例

    --gtest_also_run_disabled_tests

    执行案例时,同时也执行被置为无效的测试案例。关于设置测试案例无效的方法为:

    在测试案例名称或测试名称中添加DISABLED前缀,比如:

    // Tests that Foo does Abc.
    TEST(FooTest, DISABLED_DoesAbc) {  }

    class DISABLED_BarTest : public testing::Test {  };

    // Tests that Bar does Xyz.
    TEST_F(DISABLED_BarTest, DoesXyz) {  }

    --gtest_repeat=[COUNT]

    设置案例重复运行次数,非常棒的功能!比如:

    --gtest_repeat=1000      重复执行1000次,即使中途出现错误。
    --gtest_repeat=-1          无限次数执行。。。。
    --gtest_repeat=1000 --gtest_break_on_failure     重复执行1000次,并且在第一个错误发生时立即停止。这个功能对调试非常有用。
    --gtest_repeat=1000 --gtest_filter=FooBar     重复执行1000次测试案例名称为FooBar的案例。

     

    2. 测试案例输出

    命令行参数

    说明

    --gtest_color=(yes|no|auto)

    输出命令行时是否使用一些五颜六色的颜色。默认是auto。

    --gtest_print_time

    输出命令行时是否打印每个测试案例的执行时间。默认是不打印的。

    --gtest_output=xml[:DIRECTORY_PATH\|:FILE_PATH]

    将测试结果输出到一个xml中。

    1.--gtest_output=xml:    不指定输出路径时,默认为案例当前路径。

    2.--gtest_output=xml:d:\ 指定输出到某个目录 

    3.--gtest_output=xml:d:\foo.xml 指定输出到d:\foo.xml

    如果不是指定了特定的文件路径,gtest每次输出的报告不会覆盖,而会以数字后缀的方式创建。xml的输出内容后面介绍吧。 

     

    3. 对案例的异常处理

    命令行参数

    说明

    --gtest_break_on_failure

    调试模式下,当案例失败时停止,方便调试

    --gtest_throw_on_failure

    当案例失败时以C++异常的方式抛出

    --gtest_catch_exceptions

    是否捕捉异常。gtest默认是不捕捉异常的,因此假如你的测试案例抛了一个异常,很可能会弹出一个对话框,这非常的不友好,同时也阻碍了测试案例的运行。如果想不弹这个框,可以通过设置这个参数来实现。如将--gtest_catch_exceptions设置为一个非零的数。

    注意:这个参数只在Windows下有效。

     

    四、XML报告输出格式

    <?xml version="1.0" encoding="UTF-8"?>
    <testsuites tests="3" failures="1" errors="0" time="35" name="AllTests">
      
    <testsuite name="MathTest" tests="2" failures="1"* errors="0" time="15">
        
    <testcase name="Addition" status="run" time="7" classname="">
          
    <failure message="Value of: add(1, 1) Actual: 3 Expected: 2" type=""/>
          
    <failure message="Value of: add(1, -1) Actual: 1 Expected: 0" type=""/>
        
    </testcase>
        
    <testcase name="Subtraction" status="run" time="5" classname="">
        
    </testcase>
      
    </testsuite>
      
    <testsuite name="LogicTest" tests="1" failures="0" errors="0" time="5">
        
    <testcase name="NonContradiction" status="run" time="5" classname="">
        
    </testcase>
      
    </testsuite>
    </testsuites>

    从报告里可以看出,我们之前在TEST等宏中定义的测试案例名称(testcase_name)在xml测试报告中其实是一个testsuite name,而宏中的测试名称(test_name)在xml测试报告中是一个testcase name,概念上似乎有点混淆,就看你怎么看吧。

    当检查点通过时,不会输出任何检查点的信息。当检查点失败时,会有详细的失败信息输出来failure节点。

    在我使用过程中发现一个问题,当我同时设置了--gtest_filter参数时,输出的xml报告中还是会包含所有测试案例的信息,只不过那些不被执行的测试案例的status值为“notrun”。而我之前认为的输出的xml报告应该只包含我需要运行的测试案例的信息。不知是否可提供一个只输出需要执行的测试案例的xml报告。因为当我需要在1000个案例中执行其中1个案例时,在报告中很难找到我运行的那个案例,虽然可以查找,但还是很麻烦。

    五、总结

    本篇主要介绍了gtest案例执行时提供的一些参数的使用方法,这些参数都非常有用。在实际编写gtest测试案例时肯定会需要用到的时候。至少我现在比较常用的就是:

    1. --gtest_filter

    2.--gtest_output=xml[:DIRECTORY_PATH\|:FILE_PATH]

    3. --gtest_catch_exceptions

    最后再总结一下我使用过程中遇到的几个问题:

    1. 同时使用--gtest_filter和--gtest_output=xml:时,在xml测试报告中能否只包含过滤后的测试案例的信息。

    2. 有时,我在代码中设置testing::GTEST_FLAG(catch_exceptions) = 1和我在命令行中使用--gtest_catch_exceptions结果稍有不同,在代码中设置FLAG方式有时候捕捉不了某些异常,但是通过命令行参数的方式一般都不会有问题。这是我曾经遇到过的一个问题,最后我的处理办法是既在代码中设置FLAG,又在命令行参数中传入--gtest_catch_exceptions。不知道是gtest在catch_exceptions方面不够稳定,还是我自己测试案例的问题。

     

     

     

    /

    一、前言

    “深入解析”对我来说的确有些难度,所以我尽量将我学习到和观察到的gtest内部实现介绍给大家。本文算是抛砖引玉吧,只能是对gtest的整体结构的一些介绍,想要了解更多细节最好的办法还是看gtest源码,如果你看过gtest源码,你会发现里面的注释非常的详细!好了,下面就开始了解gtest吧。

    二、从TEST宏开始

    前面的文章已经介绍过TEST宏的用法了,通过TEST宏,我们可以非法简单、方便的编写测试案例,比如:

    TEST(FooTest, Demo)
    {
        EXPECT_EQ(
    11);
    }

     

    我们先不去看TEST宏的定义,而是先使用/P参数将TEST展开。如果使用的是VistualStudio的话:

    1. 选中需要展开的代码文件,右键 - 属性 - C/C++ - Preprocessor

    2. Generate Preprocessed File 设置Without Line Numbers (/EP /P) 或 With Line Numbers (/P)

    3. 关闭属性对话框,右键选中需要展开的文件,右键菜单中点击:Compile

    编译过后,会在源代码目录生成一个后缀为.i的文件,比如我对上面的代码进行展开,展开后的内容为:

    class FooTest_Demo_Test : public ::testing::Test 
    {
    public
        FooTest_Demo_Test() {}
    private
        
    virtual void TestBody();
        
    static ::testing::TestInfo* const test_info_;
        FooTest_Demo_Test(
    const FooTest_Demo_Test &);
        
    void operator=(const FooTest_Demo_Test &);
    };

    ::testing::TestInfo* 
    const FooTest_Demo_Test 
        ::test_info_ = 
            ::testing::
    internal::MakeAndRegisterTestInfo( 
                
    "FooTest""Demo""""",
                (::testing::
    internal::GetTestTypeId()),
                ::testing::Test::SetUpTestCase,
                ::testing::Test::TearDownTestCase,
                
    new ::testing::internal::TestFactoryImpl< FooTest_Demo_Test>);

    void FooTest_Demo_Test::TestBody()
    {
        
    switch (0)
        
    case 0:
            
    if (const ::testing::AssertionResult 
                    gtest_ar = 
                        (::testing::
    internal:: EqHelper<(sizeof(::testing::internal::IsNullLiteralHelper(1)) == 1)>::Compare("1""1"11)))
                ;
            
    else 
                ::testing::
    internal::AssertHelper(
                    ::testing::TPRT_NONFATAL_FAILURE,
                    
    ".\\gtest_demo.cpp",
                    
    9,
                    gtest_ar.failure_message()
                    ) = ::testing::Message();
    }

     

    展开后,我们观察到:

    1. TEST宏展开后,是一个继承自testing::Test的类。

    2. 我们在TEST宏里面写的测试代码,其实是被放到了类的TestBody方法中。

    3. 通过静态变量test_info_,调用MakeAndRegisterTestInfo对测试案例进行注册。

    如下图:

     

    上面关键的方法就是MakeAndRegisterTestInfo了,我们跳到MakeAndRegisterTestInfo函数中:

    // 创建一个 TestInfo 对象并注册到 Google Test;
    // 
    返回创建的TestInfo对象
    //
    // 
    参数:
    //
    //   test_case_name:           
    测试案例的名称
    //   name:                         
    测试的名称
    //   test_case_comment:      
    测试案例的注释信息
    //   comment:                     
    测试的注释信息
    //   fixture_class_id:            test fixture
    类的ID
    //   set_up_tc:                   
    事件函数SetUpTestCases的函数地址
    //   tear_down_tc:              
    事件函数TearDownTestCases的函数地址
    //   factory:                       
    工厂对象,用于创建测试对象(Test)
    TestInfo* MakeAndRegisterTestInfo(
        
    const char* test_case_name, const char* name,
        
    const char* test_case_comment, const char* comment,
        TypeId fixture_class_id,
        SetUpTestCaseFunc set_up_tc,
        TearDownTestCaseFunc tear_down_tc,
        TestFactoryBase* factory) {
      TestInfo* 
    const test_info =
          
    new TestInfo(test_case_name, name, test_case_comment, comment,
                       fixture_class_id, factory);
      GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
      
    return test_info;
    }

     

    我们看到,上面创建了一个TestInfo对象,然后通过AddTestInfo注册了这个对象。TestInfo对象到底是一个什么样的东西呢?

    TestInfo对象主要用于包含如下信息:

    1. 测试案例名称(testcase name

    2. 测试名称(test name

    3. 该案例是否需要执行

    4. 执行案例时,用于创建Test对象的函数指针

    5. 测试结果 

    我们还看到,TestInfo的构造函数中,非常重要的一个参数就是工厂对象,它主要负责在运行测试案例时创建出Test对象。我们看到我们上面的例子的factory为:

    new ::testing::internal::TestFactoryImpl< FooTest_Demo_Test>

     

    我们明白了,Test对象原来就是TEST宏展开后的那个类的对象(FooTest_Demo_Test),再看看TestFactoryImpl的实现:

    template <class TestClass>
    class TestFactoryImpl : public TestFactoryBase {
    public:
        
    virtual Test* CreateTest() { return new TestClass; }
    };

     

    这个对象工厂够简单吧,嗯,Simple is better。当我们需要创建一个测试对象(Test)时,调用factory的CreateTest()方法就可以了。 

    创建了TestInfo对象后,再通过下面的方法对TestInfo对象进行注册:

    GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);

     

    GetUnitTestImpl()是获取UnitTestImpl对象:

    inline UnitTestImpl* GetUnitTestImpl() {
        
    return UnitTest::GetInstance()->impl();
    }

     

    其中UnitTest是一个单件(Singleton),整个进程空间只有一个实例,通过UnitTest::GetInstance()获取单件的实例。上面的代码看到,UnitTestImpl对象是最终是从UnitTest对象中获取的。那么UnitTestImpl到底是一个什么样的东西呢?可以这样理解:

    UnitTestImpl是一个在UnitTest内部使用的,为执行单元测试案例而提供了一系列实现的那么一个类。(自己归纳的,可能不准确)

    我们上面的AddTestInfo就是其中的一个实现,负责注册TestInfo实例:

     

    // 添加TestInfo对象到整个单元测试中
    //
    // 
    参数:
    //
    //   set_up_tc:      
    事件函数SetUpTestCases的函数地址
    //   tear_down_tc: 事件函数TearDownTestCases的函数地址
    //   test_info:       TestInfo对象
    void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
                   Test::TearDownTestCaseFunc tear_down_tc,
                   TestInfo * test_info) {
    // 处理死亡测试的代码,先不关注它
    if (original_working_dir_.IsEmpty()) {
        original_working_dir_.Set(FilePath::GetCurrentDir());
        
    if (original_working_dir_.IsEmpty()) {
            printf(
    "%s\n""Failed to get the current working directory.");
            abort();
        }
    }
    // 获取或创建了一个TestCase对象,并将testinfo添加到TestCase对象中。
    GetTestCase(test_info->test_case_name(),
                test_info->test_case_comment(),
                set_up_tc,
                tear_down_tc)->AddTestInfo(test_info);
    }

    我们看到,TestCase对象出来了,并通过AddTestInfo添加了一个TestInfo对象。这时,似乎豁然开朗了:

    1. TEST宏中的两个参数,第一个参数testcase_name,就是TestCase对象的名称,第二个参数test_name就是Test对象的名称。而TestInfo包含了一个测试案例的一系列信息。

    2. 一个TestCase对象对应一个或多个TestInfo对象。

     

    我们来看看TestCase的创建过程(UnitTestImpl::GetTestCase):

    // 查找并返回一个指定名称的TestCase对象。如果对象不存在,则创建一个并返回
    //
    // 
    参数:
    //
    //   test_case_name:   
    测试案例名称
    //   set_up_tc:            
    事件函数SetUpTestCases的函数地址
    //   tear_down_tc:       
    事件函数TearDownTestCases的函数地址
    TestCase* UnitTestImpl::GetTestCase(const char* test_case_name,
                                        
    const char* comment,
                                        Test::SetUpTestCaseFunc set_up_tc,
                                        Test::TearDownTestCaseFunc tear_down_tc) {
      
    // test_cases里查找指定名称的TestCase
        internal::ListNode<TestCase*>* node = test_cases_.FindIf(
            TestCaseNameIs(test_case_name));

        
    if (node == NULL) {
            
    // 没找到,我们来创建一个
            TestCase* const test_case =
                
    new TestCase(test_case_name, comment, set_up_tc, tear_down_tc);

            
    // 判断是否为死亡测试案例
            if (internal::UnitTestOptions::MatchesFilter(String(test_case_name),
                                                     kDeathTestCaseFilter)) {
                
    // 是的话,将该案例插入到最后一个死亡测试案例后
               node = test_cases_.InsertAfter(last_death_test_case_, test_case);
               last_death_test_case_ = node;
            } 
    else {
                
    // 否则,添加到test_cases最后。
               test_cases_.PushBack(test_case);
               node = test_cases_.Last();
            }
        }

        
    // 返回TestCase对象
        return node->element();
    }

     

    三、回过头看看TEST宏的定义

    #define TEST(test_case_name, test_name)\
        GTEST_TEST_(test_case_name, test_name, \
                  ::testing::Test, ::testing::
    internal::GetTestTypeId())

     

    同时也看看TEST_F

    #define TEST_F(test_fixture, test_name)\
        GTEST_TEST_(test_fixture, test_name, test_fixture, \
                  ::testing::
    internal::GetTypeId<test_fixture>())

    都是使用了GTEST_TEST_宏,在看看这个宏如何定义的:

    #define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
    class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
    public:\
        GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
    private:\
        
    virtual void TestBody();\
        
    static ::testing::TestInfo* const test_info_;\
        GTEST_DISALLOW_COPY_AND_ASSIGN_(\
            GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
    };\
    \
    ::testing::TestInfo* 
    const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
        ::test_info_ =\
            ::testing::
    internal::MakeAndRegisterTestInfo(\
                #test_case_name, #test_name, 
    """", \
                (parent_id), \
                parent_class::SetUpTestCase, \
                parent_class::TearDownTestCase, \
                
    new ::testing::internal::TestFactoryImpl<\
                    GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
    void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()

     

    不需要多解释了,和我们上面展开看到的差不多,不过这里比较明确的看到了,我们在TEST宏里写的就是TestBody里的东西。这里再补充说明一下里面的GTEST_DISALLOW_COPY_AND_ASSIGN_宏,我们上面的例子看出,这个宏展开后:

    FooTest_Demo_Test(const FooTest_Demo_Test &);
    void operator=(const FooTest_Demo_Test &);

     

    正如这个宏的名字一样,它是用于防止对对象进行拷贝和赋值操作的。 

    四、再来了解RUN_ALL_TESTS

    我们的测试案例的运行就是通过这个宏发起的。RUN_ALL_TEST的定义非常简单:

    #define RUN_ALL_TESTS()\
        (::testing::UnitTest::GetInstance()->Run())

     

    我们又看到了熟悉的::testing::UnitTest::GetInstance(),看来案例的执行时从UnitTest的Run方法开始的,我提取了一些Run中的关键代码,如下:

    int UnitTest::Run() {
        __try {
            
    return impl_->RunAllTests();
        } __except(
    internal::UnitTestOptions::GTestShouldProcessSEH(
            GetExceptionCode())) {
            printf(
    "Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode());
            fflush(stdout);
            
    return 1;
        }
        
    return impl_->RunAllTests();
    }

     

    我们又看到了熟悉的implUnitTestImpl),具体案例该怎么执行,还是得靠UnitTestImpl

    int UnitTestImpl::RunAllTests() {

        
    // ...

        printer->OnUnitTestStart(parent_);

        
    // 计时
        const TimeInMillis start = GetTimeInMillis();

        printer->OnGlobalSetUpStart(parent_);
        
    // 执行全局的SetUp事件
        environments_.ForEach(SetUpEnvironment);
        printer->OnGlobalSetUpEnd(parent_);

        
    // 全局的SetUp事件执行成功的话
        if (!Test::HasFatalFailure()) {
            
    // 执行每个测试案例
            test_cases_.ForEach(TestCase::RunTestCase);
        }

        
    // 执行全局的TearDown事件
        printer->OnGlobalTearDownStart(parent_);
        environments_in_reverse_order_.ForEach(TearDownEnvironment);
        printer->OnGlobalTearDownEnd(parent_);

        elapsed_time_ = GetTimeInMillis() - start;

        
    // 执行完成
        printer->OnUnitTestEnd(parent_);

        
    // Gets the result and clears it.
        if (!Passed()) {
          failed = 
    true;
        }
        ClearResult();

        
    // 返回测试结果
        return failed ? 1 : 0;
    }

     

    上面,我们很开心的看到了我们前面讲到的全局事件的调用。environments_是一个Environment的链表结构(List),它的内容是我们在main中通过:

    testing::AddGlobalTestEnvironment(new FooEnvironment);

     

    添加进去的。test_cases_我们之前也了解过了,是一个TestCase的链表结构(List)。gtest实现了一个链表,并且提供了一个Foreach方法,迭代调用某个函数,并将里面的元素作为函数的参数:

    template <typename F>  // F is the type of the function/functor
    void ForEach(F functor) const {
        
    for ( const ListNode<E> * node = Head();
              node != NULL;
              node = node->next() ) {
          functor(node->element());
        }
    }

     

    因此,我们关注一下:environments_.ForEach(SetUpEnvironment),其实是迭代调用了SetUpEnvironment函数:

    static void SetUpEnvironment(Environment* env) { env->SetUp(); }

     

    最终调用了我们定义的SetUp()函数。

    再看看test_cases_.ForEach(TestCase::RunTestCase)的TestCase::RunTestCase实现:

    static void RunTestCase(TestCase * test_case) { test_case->Run(); }

     

    再看TestCase的Run实现:

    void TestCase::Run() {
        
    if (!should_run_) return;

        
    internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
        impl->set_current_test_case(
    this);

        UnitTestEventListenerInterface * 
    const result_printer =
        impl->result_printer();

        result_printer->OnTestCaseStart(
    this);
        impl->os_stack_trace_getter()->UponLeavingGTest();
        
    // 哈!SetUpTestCases事件在这里调用
        set_up_tc_();

        
    const internal::TimeInMillis start = internal::GetTimeInMillis();
        
    // 嗯,前面分析的一个TestCase对应多个TestInfo,因此,在这里迭代对TestInfo调用RunTest方法
        test_info_list_->ForEach(internal::TestInfoImpl::RunTest);
        elapsed_time_ = 
    internal::GetTimeInMillis() - start;

        impl->os_stack_trace_getter()->UponLeavingGTest();
        
    // TearDownTestCases事件在这里调用
        tear_down_tc_();
        result_printer->OnTestCaseEnd(
    this);
        impl->set_current_test_case(NULL);
    }

    第二种事件机制又浮出我们眼前,非常兴奋。可以看出,SetUpTestCases和TearDownTestCaess是在一个TestCase之前和之后调用的。接着看test_info_list_->ForEach(internal::TestInfoImpl::RunTest):

    static void RunTest(TestInfo * test_info) {
        test_info->impl()->Run();
    }

    哦?TestInfo也有一个impl?看来我们之前漏掉了点东西,和UnitTest很类似,TestInfo内部也有一个主管各种实现的类,那就是TestInfoImpl,它在TestInfo的构造函数中创建了出来(还记得前面讲的TestInfo的创建过程吗?):

    TestInfo::TestInfo(const char* test_case_name,
                       
    const char* name,
                       
    const char* test_case_comment,
                       
    const char* comment,
                       
    internal::TypeId fixture_class_id,
                       
    internal::TestFactoryBase* factory) {
        impl_ = 
    new internal::TestInfoImpl(this, test_case_name, name,
                                         test_case_comment, comment,
                                         fixture_class_id, factory);
    }

     

    因此,案例的执行还得看TestInfoImpl的Run()方法,同样,我简化一下,只列出关键部分的代码:

    void TestInfoImpl::Run() {

        // ...

       UnitTestEventListenerInterface* const result_printer =
            impl->result_printer();
        result_printer->OnTestStart(parent_);
        
    // 开始计时
        
    const TimeInMillis start = GetTimeInMillis();

        Test* test = NULL;

        __try {
            
    // 我们的对象工厂,使用CreateTest()生成Test对象
           test = factory_->CreateTest();
        } __except(
    internal::UnitTestOptions::GTestShouldProcessSEH(
            GetExceptionCode())) {
           AddExceptionThrownFailure(GetExceptionCode(),
                                  
    "the test fixture's constructor");
            
    return;

        }

        // 如果Test对象创建成功

        if (!Test::HasFatalFailure()) {

           // 调用Test对象的Run()方法,执行测试案例 

           test->Run();
        }

        
    // 执行完毕,删除Test对象
       impl->os_stack_trace_getter()->UponLeavingGTest();
        delete test;
        test = NULL;

        
    // 停止计时
        result_.set_elapsed_time(GetTimeInMillis() - start);
        result_printer->OnTestEnd(parent_);

    }

     

    上面看到了我们前面讲到的对象工厂fatory,通过fatory的CreateTest()方法,创建Test对象,然后执行案例又是通过Test对象的Run()方法:

    void Test::Run() {
        
    if (!HasSameFixtureClass()) return;

        
    internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
        impl->os_stack_trace_getter()->UponLeavingGTest();
        __try {
            
    // Yeah!每个案例的SetUp事件在这里调用
            SetUp();
        } __except(
    internal::UnitTestOptions::GTestShouldProcessSEH(
            GetExceptionCode())) {
            AddExceptionThrownFailure(GetExceptionCode(), 
    "SetUp()");
        }

        
    // We will run the test only if SetUp() had no fatal failure.
        if (!HasFatalFailure()) {
            impl->os_stack_trace_getter()->UponLeavingGTest();
            __try {
                
    // 哈哈!!千辛万苦,我们定义在TEST宏里的东西终于被调用了!
                TestBody();
            } __except(
    internal::UnitTestOptions::GTestShouldProcessSEH(
                GetExceptionCode())) {
                AddExceptionThrownFailure(GetExceptionCode(), 
    "the test body");
            }
        }

        impl->os_stack_trace_getter()->UponLeavingGTest();
        __try {
            
    // 每个案例的TearDown事件在这里调用
            TearDown();
        } __except(
    internal::UnitTestOptions::GTestShouldProcessSEH(
            GetExceptionCode())) {
            AddExceptionThrownFailure(GetExceptionCode(), 
    "TearDown()");
        }
    }

     

    上面的代码里非常极其以及特别的兴奋的看到了执行测试案例的前后事件,测试案例执行TestBody()的代码。仿佛整个gtest的流程在眼前一目了然了。

    四、总结

    本文通过分析TEST宏和RUN_ALL_TEST宏,了解到了整个gtest运作过程,可以说整个过程简洁而优美。之前读《代码之美》,感触颇深,现在读过gtest代码,再次让我感触深刻。记得很早前,我对设计的理解是“功能越强大越好,设计越复杂越好,那样才显得牛”,渐渐得,我才发现,简单才是最好。我曾总结过自己写代码的设计原则:功能明确,设计简单。了解了gtest代码后,猛然发现gtest不就是这样吗,同时gtest也给了我很多惊喜,因此,我对gtest的评价是:功能强大,设计简单,使用方便

    总结一下gtest里的几个关键的对象:

    1. UnitTest 单例,总管整个测试,包括测试环境信息,当前执行状态等等。

    2. UnitTestImpl UnitTest内部具体功能的实现者。

    3. Test    我们自己编写的,或通过TEST,TEST_F等宏展开后的Test对象,管理着测试案例的前后事件,具体的执行代码TestBody。

    4. TestCase 测试案例对象,管理着基于TestCase的前后事件,管理内部多个TestInfo。

    5. TestInfo  管理着测试案例的基本信息,包括Test对象的创建方法。 

    6. TestInfoImpl TestInfo内部具体功能的实现者 。


     


    转载于:https://my.oschina.net/u/3485339/blog/900322

    展开全文
  • gtest中ASSERT与EXPECT断言的区别

    千次阅读 2019-06-22 11:41:22
    参考资料查找到ASSERT断言与EXPECT断言的区别: ASSERT_* 系列的断言,当检查点失败时,退出当前函数(注意:并非退出当前案例)。...gtest文档地址: https://github.com/google/googletest/blob/mas...
  • gtest学习

    2019-09-26 15:47:46
    1.玩转Google开源C++单元测试框架Google Test系列(gtest)之一 - 初识gtest 2.玩转Google开源C++单元测试框架Google Test系列(gtest)之二 - 断言 3.玩转Google开源C++单元测试框架Google Test系列(gtest)之三 - ...
  • gtest程序设计

    2016-02-26 12:51:01
    这本书主要详细讲解了gtest程序设计的思路及文档,特别推荐,讲的很详细!
  • GTEST学习总结

    2019-03-20 09:51:02
    1.2学习文档及资料 2.gtest总结 2.1gtest中的术语 2.2断言 2.2.1基本断言 2.2.2Binary Comparison 2.2.3String comparison 2.3创建测试用例 2.4TestFixtures 2.5更多断言方法 2.6异常断言 2.7自定义输出...
  • gtest gmock

    2021-06-28 13:52:04
    文档 1. 官方文档 : https://google.github.io/googletest/ https://github.com/google/googletest 2.基于Android源码实例 https://blog.csdn.net/qq_42685012/article/details/100693675 3. 相关blog ...
  • GTest 总结

    2021-08-04 16:47:00
    Google C++单元测试框架(简称Gtest),可在多个平台上使用(包括Linux, Mac OS X, Windows, Cygwin和Symbian),它提供了丰富的断言、致命和非致命失败判断,能进行值参数化测试、类型参数化测试、“死亡测试”。...
  • Gtest框架搭建

    2018-11-26 17:26:13
    在vs2017中搭建测试框架时所遇到的问题,根据自己搭建时的过程写的文档,希望对大家有帮助
  • GTEST基础学习

    千次阅读 2016-08-14 11:25:18
    1.1 编译gtest: 下载gtest1.7.0版本,(本人通过CSDN下载),解压后,文件目录下图所示: 打开msvc文件夹,打开gtestgtest_md工程文件。进行编译。 编译方法: 如果需要生成动态库(DLL),则需要3步:...
  • gtest入门

    2014-11-20 14:17:39
    转自:http://www.habadog.com/2011/09/06/gtest-newhand-forself/
  • gtest中文指南

    2012-04-05 16:02:10
    gtest测试框架[1]是在不同平台上(Linux,Mac OS X,Windows,Cygwin,Windows CE和Symbian)为编写C++测试而生成的。它是基于xUnit架构的测试框架,支持自动发现测试,丰富的断言集,用户定义的断言,death测试,...
  • gtest-1.7.0 最新版本

    2015-07-16 23:42:43
    gtest-1.7.0 最新版本
  • gtest运行小析

    2017-07-13 16:51:00
    Gtest是google推出的C++测试框架,本篇文档,从整体上对Gtest的运行过程中的关键路径进行分析和梳理。 分析入口 新建一个最简单的测试工程,取名为source_analyse_proj,建立一个简单的测试案例,为了便于分析,可以...
  • linux下gTest笔记

    2017-02-04 16:31:28
    第一次使用gtest的一些笔记
  • gtest简介及简单使用

    万次阅读 2014-09-29 11:34:56
    gtest简介及简单使用!
  • gtest 测试框架

    千次阅读 2015-09-17 09:21:57
    本文基于笔者的实际开发经验,言简意赅地讲解了C/C++单元测试框架gtest的主要使用方法和注意事项,并设计了若干可编译的精简示例,给出了运行效果图。既可以用作gtest的入门教程,也适合作为工作中的快速参考。 AD...
  • gtest测试用例

    2020-02-18 19:24:13
    google tf测试框架代码 ... 跑单个测试例 ./sgm-test --gtest_filter=WinnerTakesAllTest.RandomLeftNormal 跑这个模块的所有测试例 ./sgm-tes...
  • gtest的安装与使用

    2021-09-15 00:03:54
    gtest的安装与使用 本篇为gtest的安装教程 点击此处查看gtest的使用教程,还没写,有空再写 开始 # 克隆仓库 # 慢的话就上proxy git clone ...
  • gtest交流与经验总结PPT,Gtest的实现机制、运行参数和实践案例,一些小技巧的分享。
  • 网上太多教程,基于cmake,对于直接make生成gtest.a gmock.a写的太模糊或者太复杂,所以整理一篇文档,帮助大家快速入门 github下载googletest源码 切换到tag,找一个版本下载: cmake编译gooleetest源码生成...
  • gtest使用手册中文版

    2015-04-09 09:53:19
    gtest单元测试框架,中文版使用手册,大概讲解了使用方法,简单易学
  • gtest和gmock入门

    万次阅读 2016-02-17 10:19:57
    网上的例子很多都过多强调概念,本文用一个简单的例子让大家对于什么是 gtest 和 gmock 让大家有一个直观的了解,让大家很快上手,就像写 hello word 一样容易。 gtest&gmock 的 1.6 版本的使用 make 编译,新版的...
  • GTest测试框架使用

    千次阅读 2020-04-26 15:08:38
    Gtest框架简介 Gtest是Google Test的简称,是Google开发的C++单元测试框架; 适用于多个平台: Liunx, Mac OS X, Windows, Cygwin, Windows CE and Symbian, PlatformIO Gtest 是基于xUnit框架编写,和Junit, ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,855
精华内容 742
关键字:

gtest文档