日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

用google mock模拟C++对象

發(fā)布時間:2024/2/28 c/c++ 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用google mock模拟C++对象 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

google mock是用來配合google test對C++項目做單元測試的。它依賴于googletest(參見我上篇文章《如何用googletest寫單元測試》:?http://blog.csdn.net/russell_tao/article/details/7333226),下面我來說說linux上怎么用它來做單元測試。

本文包括:1、如何獲取、編譯google mock;2、如何使用gmock(下面用gmock來代稱google mock)配合gtest做單元測試。


1、如何獲取、編譯google mock

gmock的當前版本與gtest一樣,是1.6.0。可以從這個網(wǎng)址獲取:http://code.google.com/p/googlemock/downloads/list。

下載到壓縮包解壓后,下面我們開始編譯出靜態(tài)庫文件(必須得自己編譯出),以在我們自己的單元測試工程中使用。

與gtest相同,我們執(zhí)行完./configure; make后,不能執(zhí)行make install,理由與上篇相同。

驗證這個包有沒有問題,依然可以執(zhí)行如下命令:

[cpp]?view plaincopy
  • cd?make??
  • make??
  • ./gmock_test??

  • 如果你看到類似下文的輸出屏幕,證明你的機器運行g(shù)mock沒有問題。

    [cpp]?view plaincopy
  • [----------]?Global?test?environment?tear-down??
  • [==========]?13?tests?from?3?test?cases?ran.?(2?ms?total)??
  • [??PASSED??]?13?tests.??

  • 這時還沒有編譯出我們要的libgmock.a呢。繼續(xù)在gmock解包目錄下執(zhí)行:

    [cpp]?view plaincopy
  • g++?-I?gtest/include/?-I?gtest/?-I?include/?-I?./?-c?gtest/src/gtest-all.cc???
  • g++?-I?gtest/include/?-I?gtest/?-I?include/?-I?./?-c?src/gmock-all.cc?????????
  • ar?-rv?libgmock.a?gtest-all.o?gmock-all.o???

  • 如此,當前目錄下會鏈接出我們需要的libgmock.a。注意,這個gmock.a靜態(tài)庫里,把gtest需要的gtest-all.cc都編譯進來了,所以我們的單元測試工程只需要鏈接libgmock,不再需要鏈接上文說的libgtest了。


    2、如何使用gmock

    首先,編譯我們自己的單元測試工程時,需要在makefile里加入以下編譯選項:-I${GTEST_DIR}/include -I${GMOCK_DIR}/include,這兩個目錄我們自己從上面的包里拷貝出來即可。鏈接時,需要加上libgmock.a。


    還是以一個例子來說明怎么在mock對象的情況下寫單元測試。


    我現(xiàn)在有一個生產(chǎn)者消費者網(wǎng)絡(luò)模型,消費者(例如client)會先發(fā)TCP請求到我的SERVER去訂閱某個對象。生產(chǎn)者(另一臺SERVER)產(chǎn)生關(guān)于某個對象的事件后發(fā)給我的SERVER后,我的SERVER再把事件發(fā)給消費者。

    就是這么簡單。


    我現(xiàn)在想寫一個單元測試,主要測試代碼邏輯,不想去管網(wǎng)絡(luò)包的收發(fā)這些事情。

    我現(xiàn)在有兩個類,一個叫CSubscriber,它封裝為一個訂閱的消費者,功能主要是操作網(wǎng)絡(luò),包括網(wǎng)絡(luò)收發(fā)包,協(xié)議解析等。另一個叫CSubEventHandler,它主要做邏輯處理,去操作CSubscriber對象,例如epoll返回讀事件后,會構(gòu)造一個CSubscriber對象,然后CSubEventHandler::handleRead方法就來處理這個CSubscriber對象。


    我單元測試的目的是,測試CSubEventHandler::handleRead的業(yè)務(wù)邏輯,我同時也想測試CSubscriber方法里的協(xié)議解析邏輯,但是對于CSubscriber封裝的讀寫包部分,我希望可以mock成我想要的網(wǎng)絡(luò)包。

    怎么做呢?

    a)、先mock一個CSubscriber類如下:

    [cpp]?view plaincopy
  • class?MockCSubscriber?:?public?CSubscriber??
  • {??
  • public:??
  • ????MockCSubscriber(int?fd):CSubscriber(fd){}??
  • ????MOCK_METHOD1(readBuf,?int(int?len));??
  • ????MOCK_METHOD1(writeBuf,?int(int?len));??
  • ????MOCK_METHOD0(closeSock,?void());??
  • };??

  • 其中,CSubscriber的構(gòu)造方法必須有一個int型的fd,而readBuf和writeBuf都只接收一個int型的參數(shù),而closeSock方法 沒有參數(shù)傳遞。于是我使用了MOCK_METHOD0和MOCK_METHOD1這兩個宏來聲明想MOCK的方法。這兩個宏的使用很簡單,解釋下:

    MOCK_METHOD#1(#2, #3(#4) )

    #2是你要mock的方法名稱!#1表示你要mock的方法共有幾個參數(shù),#4是這個方法具體的參數(shù),#3表示這個方法的返回值類型。

    很簡單不是?!


    b)、如果只關(guān)心mock方法的返回值。

    這里用到一個宏ON_CALL。看例子:

    [cpp]?view plaincopy
  • ON_CALL(subObj,?readBuf(1000)).WillByDefault(Return(blen));??

  • 什么意思呢?再用剛才的解釋方法:

    ON_CALL(#1, #2(#3)).WillByDefault(Return(#4));

    #1表示mock對象。就像我上面所說,對CSubscriber我定義了一個Mock類,那么就必須生成相應(yīng)的mock對象,例如:

    [cpp]?view plaincopy
  • MockCSubscriber?subObj(5);??

  • #2表示想定義的那個方法名稱。上例中我想定義readBuf這個方法的返回值。

    #3表示readBuf方法的參數(shù)。這里的1000表示,只有調(diào)用CSubscriber::readBuf同時傳遞參數(shù)為1000時,才會用到ON_CALL的定義。

    #4表示調(diào)用CSubscriber::readBuf同時傳遞參數(shù)為1000時,返回blen這個變量的值


    c)、如果還希望mock方法有固定的被調(diào)用方式

    這里用到宏EXPECT_CALL,看個例子:

    [cpp]?view plaincopy
  • EXPECT_CALL(subObj,?readBuf(1000)).Times(1);??

  • 很相似吧?最后的Times表示,只希望readBuf在傳遞參數(shù)為1000時,被調(diào)用且僅被調(diào)用一次。


    其實這些宏有很復(fù)雜的用法的,例如:

    [cpp]?view plaincopy
  • EXPECT_CALL(subObj,?readBuf(1000))??
  • ????.Times(5)??
  • ????.WillOnce(Return(100))??
  • ????.WillOnce(Return(150))??
  • ????.WillRepeatedly(Return(200));??

  • 表示,readBuf希望被調(diào)用五次,第一次返回100,第二次返回150,后三次返回200。如果不滿足,會報錯。


    d)、實際的調(diào)用測試

    其實調(diào)用跟上篇googletest文章里的測試是一致的,我這里只列下上文的完整用例代碼(不包括被測試類的實現(xiàn)代碼):

    [cpp]?view plaincopy
  • #include?"gtest/gtest.h"??
  • #include?"gmock/gmock.h"??
  • #include?"CSubscriber.h"??
  • #include?"CPublisher.h"??
  • #include?"CSubEventHandler.h"??
  • #include?"CPubEventHandler.h"??
  • ??
  • using?::testing::AtLeast;??
  • using?testing::Return;??
  • ??
  • ??
  • class?MockCSubscriber?:?public?CSubscriber??
  • {??
  • public:??
  • ????MockCSubscriber(int?fd):CSubscriber(fd){}??
  • ????MOCK_METHOD1(readBuf,?int(int?len));??
  • ????MOCK_METHOD1(writeBuf,?int(int?len));??
  • ????MOCK_METHOD0(closeSock,?void());??
  • };??
  • ??
  • class?MockCPublisher?:?public?CPublisher??
  • {??
  • public:??
  • ????MockCPublisher(int?fd):CPublisher(fd){}??
  • ????MOCK_METHOD1(readBuf,?int(int?len));??
  • ????MOCK_METHOD1(writeBuf,?int(int?len));??
  • ????MOCK_METHOD0(closeSock,?void());??
  • };??
  • ??
  • ??
  • TEST(subpubHandler,?sub1pub1)?{??
  • ????MockCSubscriber?subObj(5);??
  • ????MockCPublisher?pubObj(5);??
  • ??
  • ????subObj.m_iRecvBufLen?=?1000;??
  • ????pubObj.m_iRecvBufLen?=?1000;??
  • ??
  • ????char*?pSubscribeBuf?=?"GET?/?HTTP/1.1\r\nobject:?/tt/aa\r\ntime:?112\r\n\r\n";??
  • ????char*?pMessageBuf?=?"GET?/?HTTP/1.1\r\nobject:?/tt/aa\r\ntime:?112\r\nmessage:?tttt\r\n\r\n";??
  • ????subObj.m_pRecvBuf?=?pSubscribeBuf;??
  • ????int?blen?=?strlen(pSubscribeBuf);??
  • ????subObj.m_iRecvPos?=?blen;??
  • ??
  • ????pubObj.m_pRecvBuf?=?pMessageBuf;??
  • ????int?mlen?=?strlen(pMessageBuf);??
  • ????pubObj.m_iRecvPos?=?mlen;??
  • ??
  • ??
  • ????ON_CALL(subObj,?readBuf(1000)).WillByDefault(Return(blen));??
  • ????ON_CALL(subObj,?writeBuf(CEventHandler::InternalError.size())).WillByDefault(Return(0));??
  • ??
  • ????CSubEventHandler?subHandler(NULL);??
  • ????CPubEventHandler?pubHandler(NULL);??
  • ??
  • ????CHashTable?ht1(100);??
  • ????CHashTable?ht2(100);??
  • ????subHandler.initial(100,?&ht1,?&ht2);??
  • ????pubHandler.initial(100,?&ht1,?&ht2);??
  • ??
  • ????EXPECT_CALL(subObj,?readBuf(1000)).Times(1);??
  • ????//EXPECT_CALL(subObj,?closeSock()).Times(1);??
  • ????EXPECT_CALL(subObj,?writeBuf(4)).Times(1);??
  • ??
  • ????EXPECT_TRUE(subHandler.handleRead(&subObj));??
  • ??
  • ????ON_CALL(pubObj,?readBuf(1000)).WillByDefault(Return(mlen));??
  • ????ON_CALL(pubObj,?writeBuf(4)).WillByDefault(Return(0));??
  • ??
  • ????EXPECT_CALL(pubObj,?readBuf(1000)).Times(1);??
  • ????EXPECT_CALL(pubObj,?closeSock()).Times(1);??
  • ????EXPECT_CALL(pubObj,?writeBuf(CEventHandler::Success.size())).Times(1);??
  • ??
  • ????EXPECT_TRUE(pubHandler.handleRead(&pubObj));??
  • }??

  • CSubscriber的頭文件:

    [cpp]?view plaincopy
  • class?CSubscriber?:?public?CBaseConnection,?public?CHashElement??
  • {??
  • public:??
  • ????CSubscriber(int?fd);??
  • ??????
  • ????virtual?~CSubscriber();??
  • ??
  • ????bool?initial();??
  • ??
  • ????bool?reset();??
  • ??
  • ????//function?return:??
  • ????//0:?means?complete?read,?all?elements?parsed?OK??
  • ????//1:?means?it?need?recv?more?buf,?not?it's?not?complete??
  • ????//-1:?means?the?packet?is?not?valid.??
  • ????//-2:?means?connection?wrong.??
  • ????int?readPacket();??
  • ??
  • ????//max?send?buf?length??
  • ????static?int?m_iSendBufLen;??
  • ??
  • ????//max?recv?buf?length??
  • ????static?int?m_iRecvBufLen;??
  • ??
  • private:??
  • ????/*request?format:?
  • ?????*?GET?/objectname?ts=xxx?HTTP/1.x\r\n\r\n*/??
  • ????bool?parsePacket();??
  • };??


  • e)、main函數(shù)的寫法

    與gtest相同,唯一的區(qū)別是初始化參數(shù),如下:

    [cpp]?view plaincopy
  • #include?<gmock/gmock.h>??
  • ??
  • int?main(int?argc,?char**?argv)?{??
  • ????testing::InitGoogleMock(&argc,?argv);??
  • ????//testing::InitGoogleTest(&argc,?argv);??
  • ??
  • ????//?Runs?all?tests?using?Google?Test.??
  • ????return?RUN_ALL_TESTS();??
  • }??

  • 如此,就可以完整的使用googletest/googlemock做C++工程的單元測試了,確實很簡單好用。

    總結(jié)

    以上是生活随笔為你收集整理的用google mock模拟C++对象的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。