2016-11-03 138 views
1

我有一些基於googlemock框架的單元測試的遺留代碼。當我試圖單元測試一些新的情況下延長我遇到了以下問題:使用googlemock與假虛擬impls的非虛函數

class D 
{ 
public: 
    void pubMethod1(); 
    int pubMethod2(); 
    // There are pretty much non-virtual methods, both public and private 
    ... 
protected: 
    uint method3(); 
    void method4(); 
    ... 
    // Some class members are here 
}; 

class SUT 
{ 
public: 
    ... 
protected: 
    D _dep; 
}; 

的SUT類(測試軟件)應進行測試,其執行文件sut.cpp定義。 SUT依賴於D類,其實現在文件d.cpp中。爲了減少鏈接器依賴關係,我不想在測試中添加d.cpp,所以當鏈接測試時,D的成員有很多'未定義符號'錯誤。爲了消除錯誤並提供可預測的行爲,我將在測試中爲D的方法創建假實現。但是,直到D的方法是虛擬的,我仍然無法使用它的所有googlemock的功能。

我喜歡從googlemock框架中使用WillOnce,AtLeast,WillRepeatedly,Invoke等功能的想法,因爲它使單元測試的創建變得更容易。問題是我不喜歡改變D的界面,把它的方法變成虛擬界面。是否有可能使用googlemock函數與假實現我要爲D的方法創建?

注意:我已經考慮過使用模板化SUT類的解決方案,但是我想知道是否存在其他解決方案。

回答

0

首先 - 最好的是重新設計你的SUT類,使其通過一些抽象接口進行D注入。因爲我下面介紹的解決方法是真正棘手 - 所以不那麼容易維護和未來的瞭解...


如果你想使你的d類的假implememtation在UT目標 - 那麼你就可以爲D製作Mock類:DMock。這DMock將不會與D - 不是從它派生 - 但它需要與真正/假的D對象配對。

所以 - 看到的例子:

創建DMock - 模仿的d接口(請注意,您應該嘲笑只有公共職能 - 因爲你的SUT只使用公共的):

class DMock 
{ 
public: 
    MOCK_METHOD0(pubMethod1, void()); 
    MOCK_METHOD0(pubMethod2, int()); 
}; 

配對與DMock對象實(但假的)d的對象 - 是這樣的:

class DMockRepo 
{ 
public: 
    // for UT 
    void addMockToUse(DMock* dMock) { freeMock.push_back(dMock); } 

    // for implementing D fake methods 
    DMock& getMock(D* original) 
    { 
     // TODO: use more sophisticated way to add mock to map... 
     if (not usedMock[original]) 
     { 
      usedMock[original] = freeMock.front(); 
      freeMock.pop_front(); 
     } 
     return *useddMock[original]; 
    } 
    static DMockRepo& getInstance() { return instance; } //singleton 
private: 
    DMockRepo() {} // private 
    static DMockRepo instance; 
    std::map<D*,DMock*> usedMock; 
    std::deque<DMock*> freeMock; 
}; 

使用模擬,以製造假執行d類的公共方法:

void D::pubMethod1() 
{ 
    DMockRepo::getInstance().getMock(this).pubMethod1(); 
} 
// 

非公共方法是不相關的 - 所以做任何你喜歡...

並使用DMockRepo設定期望您d對象:

TEST(Usage,Example) 
{ 
    DMock dMock; 
    DMockRepo::getInstance().addMockToUse(&dMock); 
    SUT sut; // you should know how many D objects SUT needs - I assume just one 

    EXPECT_CALL(dMock, pubMethod1()); 
    sut.doSomethingThatCallsDpubMethod1(); 
} 
+0

談到通過一個抽象的注入d接口。我認爲我有某種恐懼症,但似乎有一個抽象界面與唯一的派生類似乎很奇怪。另一方面,我明白這種方法在單元測試中的優點。所以我不能決定使用這種方法)) – Rom098

+1

用這種方式來思考這個問題:代碼應該具有實現的功能 - >唯一的證明功能在於它被測試 - >可測試性很重要 - >應以可測試的方式設計實施。因此,添加一些「只是爲了測試」是沒有錯的... – PiotrNycz

+0

聽起來不錯))我接受了你的答案,既好的建議和技巧。 – Rom098