gmock學習02---編寫自己的Matcher與如何讓編譯器識別被mock的重載函數


本文目的

gmock框架中自帶Matcher只針對c++內置類型,如string,int,float等等,有時候無法滿足項目要求,所以需要編寫自己的Matcher對象。本文介紹如何使用gmock提供的Matcher宏快速編寫自己的Matcher對象。

在測試重載的mock函數時,需要對Matcher做特別的封裝,否則編譯在查找重載函數時會出現歧義。

 

 

待測的對象

/*
 * 文件Base.h
 *
 *  Created on: 2011-10-1
 *      Author: bourneli
 */

#ifndef BASE_H_
#define BASE_H_

#include <iostream>
#include <string>
using namespace std;

class Param
{
public:
    int n1;
    double f1;
};

class Dependence
{
public:

    virtual ~Dependence(){}

    virtual void show() const
    {
        cout << "I am a dependence of Foo" << endl;
    }

    virtual void show(const string& sSth) const
    {
        cout << "show: " << sSth << endl;
    }

    virtual void show(const Param& oParam) const
    {
        cout << oParam.n1 << endl;
        cout << oParam.f1 << endl;
    }
};

/*
 * 調用mock的對象
 */
class Foo
{
public:

    void showVoid(const Dependence& oDep)const
    {
        oDep.show();
    }

    void showString(const Dependence& oDep, const string& sSth)const
    {
        oDep.show(sSth);
    }

    void showParam(const Dependence& oDep, const Param& oParam)const
    {
        oDep.show(oParam);
    }

};

#endif /* BASE_H_ */

類Dependece有三個重載函數:

  • void show(void)
  • void show(const string&)
  • void show(const Param&)

需要編寫Dependence的Mock對象,用於測試類Foo,類Foo也分別有三個方法調用類Dependence不同的重載方法:

  • void showVoid(const Dependence&) --- 調用Dependence::show(void)
  • void showString(const Dependence&, const string&) --- 調用Dependence::show(const string&)
  • void showParam(const Dependence&, const Param&) --- 調用Dependence::show(const Param&)

還有一個類Param,這是一個自定義類,需要自己編寫Param的Matcher對象。在這里,匹配邏輯為:如果兩個Param對象的n1屬性相同,那么就匹配。

 

編寫自己的Matcher

編寫自己的Matcher對象在gmock1.4后變得很容易,gmock框架為我們做了大部分的事情,看看如下的代碼:

// custom matcher
MATCHER_P(ParamObjMatcher, oParam, "")
{
    const Param& op = (const Param&)arg;
    return op.n1 == oParam.n1;
}

只用了兩行代碼,就完成了自定義Matcher。MATCHER_P中的P代表參數,MATCHER_P其實應該寫成“MATCHER_P1”,表示該matcher的構造函數只接受一個參數,同樣的還有“MATCHER_P2、MATCHER_P3,..., MATCHER_P10”。宏的第一個參數代表該Matcher的類名,第二個參數代表Matcher的構造函數中的第一個參數,最后一個空內容的字符代表失敗時輸出信息,為空那么gmock會默認為你填寫相關信息。arg是這個宏中的一個參數,代表被匹配的對象,在這里也就是“cosnt Param&”。Dependence類的mock對象如下,詳細信息可以參見文章《gmock學習01---Linux配置gmock》。

/*
 * 文件Dependence_mock.h
 *
 *  Created on: 2011-10-1
 *      Author: bourneli
 */

#ifndef DEPENDENCE_MOCK_H_
#define DEPENDENCE_MOCK_H_

#include <string>
#include "gmock/gmock.h"
#include "Base.h"

// mock class
class DependenceMock: public Dependence
{
public:
    MOCK_CONST_METHOD0(show, void());
    MOCK_CONST_METHOD1(show, void(const string&));
    MOCK_CONST_METHOD1(show, void(const Param&));
};

// custom matcher
MATCHER_P(ParamObjMatcher, oParam, "")
{
    const Param& op = (const Param&)arg;
    return op.n1 == oParam.n1;
}

#endif /* DEPENDENCE_MOCK_H_ */

 

編寫測試用例

mock的相關工作完成后,可以編寫測試用例,首先看看測試用例的源代碼,如下:

/*
 * 文件DependenceUT.cpp
 *
 *  Created on: 2011-10-1
 *      Author: bourneli
 */

#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "Dependence_mock.h"
#include "Base.h"

using ::testing::MatchesRegex;
using ::testing::Matcher; 

TEST(DependenceTestSuite, ShowVoidTestCase)
{
    DependenceMock oMock;
    EXPECT_CALL(oMock, show());

    Foo oFoo;
    oFoo.showVoid(oMock);
}

TEST(DependenceTestSuite, ShowStringTestCase)
{
    DependenceMock oMock;
    EXPECT_CALL(oMock, show(Matcher<const string&> // 注意這里 
         (MatchesRegex(".*error.*"))));

    Foo oFoo;
    oFoo.showString(oMock, "error happened in log");
}

TEST(DependenceTestSuite, ShowParamTestCase)
{
    DependenceMock oMock;

    Param op;
    op.n1 = 1;
    op.f1 = 0.1;
    EXPECT_CALL(oMock, show(Matcher<const Param&>   // 注意這里
         (ParamObjMatcher(op))));

    Foo oFoo;
    op.f1 = 0.2; // 沒有任何影響,因為只比較n1
    oFoo.showParam(oMock, op);
}

上面特別需要注意的地方是標有“注意這里”注釋的代碼,意義在於標記出該Matcher對象對應的類,這樣編譯器就可以根據類找到特定的重載函數。比如,MatchesRegex這個Matcher對象被Matcher<const string&>封裝后,編譯器就知道是調用void show(const string&)這個重載函數,同理對應我們的自定義Matcher ParamObjMatcher。這里還有一個小技巧,你可以在自定義Matcher中使用GTEST的相關斷言,這樣可以方便的驗證自定義對象中的值。

 

 

結論

  1. 使用宏MATCHER_P快速編寫自己的Matcher對象。
  2. 使用Matcher<T>指定Matcher對象對應的類型,告知編譯器如何在重載函數查找特定的函數。
  3. 在自定義Matcher中使用gtest斷言,可以方便驗證mock函數的輸入否和期望。

 

相關資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM