Google单元测试工具gtest和gmoke简介

1、安装gtest

$sudo apt-get install libgtest-dev

$cd /usr/src/gtest

$sudo cmake .

$sudo make

$sudo cp libgtest*.a /usr/local/lib

2、gtest使用例子

#include<iostream>
#include<gtest/gtest.h>

using namespace std;

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,Delete12123)
{
    ASSERT_FALSE(link.pHead == NULL);
    ASSERT_TRUE(link.Delete(3) == true);
    ASSERT_TRUE(link.Delete(9) == false);
}

TEST(Test, simple)
{
    ASSERT_EQ(1,1);
}

int main(int argc,char *argv[])
{
    testing::InitGoogleTest(&argc,argv);
    return RUN_ALL_TESTS(); //开始所有测试
}

编译:
g++ test.cpp -lgtest -lpthread -o test

执行结果:


说明:

1. TEST(test_case_name, test_name) TEST_F(test_fixture, test_name)
TEST宏的作用是创建一个简单测试,它定义了一个测试函数,在这个函数里可以使用任何C++代码并使用提供的断言来进行检查。

TEST_F与TEST的区别是,TEST_F提供了一个初始化函数(SetUp)和一个清理函数(TearDown),在TEST_F中使用的变量可以在初始化函数SetUp中初始化,在TearDown中销毁,并且所有的TEST_F是互相独立的,都是在初始化以后的状态开始运行,一个TEST_F不会影响另一个TEST_F所使用的数据

2.  gtest中,断言的宏可以分为两类,一类是ASSERT系列,一类是EXPECT系列。{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 >= v2EXPECT_*和ASSERT_*的区别:(1)、EXPECT_*失败时,案例继续往下执行;(2)、ASSERT_*失败时,直接在当前函数中返回,当前函数中ASSERT_*后面的语句将不会执行,退出当前函数,并非退出当前案例。断言:布尔值检查、数值型数据检查、字符串检查、显示成功或失败、异常检查、Predicate Assertions、浮点型检查、Windows HRESULT assertions、类型检查。

3.  ::testing::InitGoogleTest(&argc,argv)gtest的测试案例允许接收一系列的命令行参数,将命令行参数传递给gtest,进行一些初始化操作。gtest的命令行参数非常丰富。命令行参数:(1)、--gtest_list_tests:使用这个参数时,将不会执行里面的测试案例,而是输出一个案例的列表;(2)、--gtest_filter:对执行的测试案例进行过滤,支持通配符;(3)、--gtest_also_run_disabled_tests:执行案例时,同时也执行被置为无效的测试案例;(4)、--gtest_repeat=[COUNT]:设置案例重复运行次数;(5)、--gtest_color=(yes|no|auto):输出命令行时是否使用一些五颜六色的颜色,默认是auto;(6)、--gtest_print_time:输出命令时是否打印每个测试案例的执行时间,默认是不打印的;(7)、--gtest_output=xml[:DIRECTORY_PATH\|:FILE_PATH:将测试结果输出到一个xml中,如—gtest_output=xml:d:\foo.xml  指定输出到d:\foo.xml ,如果不是指定了特定的文件路径,gtest每次输出的报告不会覆盖,而会以数字后缀的方式创建;(8)、--gtest_break_on_failure:调试模式下,当案例失败时停止,方便调试;(9)、--gtest_throw_on_failure:当案例失败时以C++异常的方式抛出;(10)、--gtest_catch_exceptions:是否捕捉异常,gtest默认是不捕捉异常的,这个参数只在Windows下有效。

4.  gtest的事件一共有3种(1)、全局的,所有案例执行前后;(2)、TestSuite级别的,在某一批案例中第一个案例前,最后一个案例执行后;(3)、TestCase级别的,每个TestCase前后。

全局事件:要实现全局事件,必须写一个类,继承testing::Environment类,实现里面的SetUp和TearDown方法。SetUp方法在所有案例执行前执行;TearDown方法在所有案例执行后执行。
TestSuite事件:需要写一个类,继承testing::Test,然后实现两个静态方法:(1)、SetUpTestCase方法在第一个TestCase之前执行;(2)、TearDownTestCase方法在最后一个TestCase之后执行。
TestCase事件:是挂在每个案例执行前后的,需要实现的是SetUp方法和TearDown方法。(1)、SetUp方法在每个TestCase之前执行;(2)、TearDown方法在每个TestCase之后执行。
每个基于gtest的测试过程,是可以分为多个TestSuite级别,而每个TestSuite级别又可以分为多个TestCase级别。这样分层的结构的好处,是可以针对不同的TestSuite级别或者TestCase级别设置不同的参数、事件机制等,并且可以与实际测试的各个模块层级相互对应,便于管理。

5.  可以通过操作符"<<"将一些自定义的信息输出
如在EXPECT_EQ(v1, v2)<< "thisis a error! "

6.  参数化
必须添加一个类,继承testing::TestWithParam<T>,其中T就是你需要参数化的参数类型。

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

8.  testing::AddGlobalTestEnvironment(newFooEnvironment)
在main函数中创建和注册全局环境对象。


3、安装gmock

$sudo apt-get install google-mock

$cd /usr/src/gmock

$sudo cmake .

$sudo make

$sudo cp lib*.a /usr/local/lib

4、使用gmock例子

Messenger.h

#ifndef SRC_MESSENGER_H_
#define SRC_MESSENGER_H_

#include <string>
using namespace std;

class Messenger
{
public:
    virtual ~Messenger() {}
    virtual string getMessage() = 0;
}; 
#endif /* SRC_MESSENGER_H_ */

MockMessenger.h

#ifndef SRC_MOCKMESSENGER_H_
#define SRC_MOCKMESSENGER_H_

#include "Messenger.h"
#include <string>
#include <gmock/gmock.h>
using namespace std;

class MockMessenger : public Messenger
{
public:
    MOCK_METHOD0(getMessage, string());
};

#endif /* SRC_MOCKMESSENGER_H_ */

HelloWorld.cpp

#include "HelloWorld.h"
#include "Messenger.h"

HelloWorld::HelloWorld()
{
}

HelloWorld::~HelloWorld()
{
}

string HelloWorld::getMessage(Messenger* messenger) const
{
    return messenger->getMessage();
}

HelloWorld.h

#ifndef SRC_HELLOWORLD_H_
#define SRC_HELLOWORLD_H_

#include <string>
#include "MockMessenger.h"
using namespace std;

class HelloWorld
{
public:
    HelloWorld();
    virtual ~HelloWorld();
    string getMessage(Messenger* messenger) const;
};

#endif /* SRC_HELLOWORLD_H_ */
HelloWorld_UnitTest.cpp
#include "HelloWorld.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "MockMessenger.h"
#include <string>
#include <memory>
using namespace testing;

TEST(HelloWorldTest, getMessage)
{
    MockMessenger messenger;
    std::string msg = "Hello World";
    EXPECT_CALL(messenger, getMessage()).WillRepeatedly(Return(ByRef(msg)));

    HelloWorld helloWorld;
    EXPECT_EQ("Hello World", helloWorld.getMessage(&messenger));
    EXPECT_EQ("Hello World", helloWorld.getMessage(&messenger));
    EXPECT_EQ("Hello World", helloWorld.getMessage(&messenger));
}

int main(int argc, char** argv)
{
    testing::InitGoogleMock(&argc, argv);
    return RUN_ALL_TESTS();
}

编译:

g++ HelloWorld.cpp HelloWorld_UnitTest.cpp -lgtest -lpthread -lgmock -o test

执行结果:


说明:

Google Mock的作用是帮你快速地做出一个接口的仿制品。
如果你的设计依赖其它的类,而这些类还没有完成或非常昂贵(如数据库);

如果你要测试你的模块与其它模块是否能正确结合,并想了解其交互过程;那么Google Mock就能帮助你。

例子中Messenger.h是一个没有完成功能的接口,由MocMessenger.h模拟完成

几个宏的说明:
MOCK_METHOD#1(#2, #3(#4) )
#1表示你要mock的方法共有几个参数
#2是你要mock的方法名称
#3表示这个方法的返回值类型
#4是这个方法具体的参数
以上就已经完成了对接口类的mock,但打桩的工作还没有全部完成,还需要设置某个成员函数执行时能按我们的期望来返回值,我们继续往下看。
选择一个要进行单元测试的文件s_ls_dosomething.cpp,里面只有一个函数:
再新建一个s_ls_dosomething_ut.cpp作为s_ls_dosomething.cpp这个文件中函数单元测试文件,内容如下:
之前在完成interface_mock.cpp的时候说打桩还没有全部完成,剩下的工作就在这个TEST中了,就是通过ON_CALL/ EXPECT_CALL来设定桩函数的返回值,这2个宏的具体说明如下:

ON_CALL(#1, #2(#3)).WillByDefault(Return(#4));
#1表示mock对象
#2表示想定义的那个方法名称。
#3表示定义方法的参数,只有当传入的参数=#3的值时,才会生效,也可用_,表示匹配任何参数输入都生效
#4表示调用要返回值。
除了ON_CALL以外,还有EXPECT_CALL(#1, #2(#3)),参数含义同ON_CALL,还可以有额外的功能,比如:

EXPECT_CALL(#1, #2(#3)).Times(5).WillOnce(Return(100))
.WillOnce(Return(150))
.WillRepeatedly(Return(200));
表示第一次返回100,第二次调用返回150,后面全部返回200,以此类推。
ON_CALL和EXCEPT_CALL相当于设置桩函数的属性设置,因此应当在桩函数调用前进行设置。


  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值