程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> mock non-virtual methods,mocknon-virtual

mock non-virtual methods,mocknon-virtual

編輯:C++入門知識

mock non-virtual methods,mocknon-virtual


生產代碼中有很多類方法是非虛的,而為了在Gtest中解除這些非必需的依賴,可以通過Gmock的mock non-virtual methods using templates方法來達到目的。
在此之前,需要了解一種設計模式:Dependency Injection,依賴注入。雖然這個概念始於Java和.net,但在面向對象編程中,C++代碼同樣應該遵循。

Ps:軟件工程中的一個重要的理念就是關注分離(Separation of concern, SoC)。依賴注入不是目的,它是一系列工具和手段,最終的目的是幫助我們開發出松散耦合(loose coupled)、可維護、可測試的代碼和程序。這條原則的做法是大家熟知的面向接口,或者說是面向抽象編程。

 

如何重構代碼達到DI的目的呢,下面是一個例子。
原代碼:

class A{
public:
  int Funtion1(B& obj) {
    //do something
    std::string str = “mock non-virtual methods using templates”;
     auto rst = obj.Function2(str);
    //do something
  }
}

 

class B{
public:
    int Funtion2(std::string _str){ puts(_str.c_str()); }
}

 

當我們對類A的方法Function1進行UT防護的時候,不關心其中類B的方法Function2的執行結果,這時候該如何對其進行mock呢(Function2是非虛的)?

在以上這種代碼結構中,答案是無法進行mock!除非把Function2修改為virtual或者使用下面的方法:
修改後:

emplate <class T1 >
class  RefactorA{
public:
  int Funtion1(T1 & obj) {
    //do something
    std::string str = “mock non-virtual methods using templates”;
    auto rst = obj.Function2(str);
    //do something
  }
}

重構之後,類RefactorA變成了類模板,在實例化的時候把依賴的類B顯式的“注入”進去,這時候進行UT的時候,就可以把“注入”的類B的方法Function2 進行mock,代碼如下:
//對類B中的Function2進行mock

class  mockB
{
public:
  MOCK_METHOD1(Funtion2, int (std::string ));
};

/對類A進行UT測試

class RefactorA _UT : public :: testing::Test
{
protected:
  virtual void SetUp(){}
  virtual void TearDown(){}

  RefactorA < mockB > mockObjA;//實例化模板類
};
 
TEST_F(RefactorA _UT , Funtion1)
{
  //期望類B的方法Function2被調用至少一次,返回值為100,參數為任意字符串
  mockB  mockObjB;
  EXPECT_CALL(mockObjB, Funtion2 (_))
  .Times(AtLeast(1))
  .WillOnce(Return(100));

  auto  rst  =  mockObjA.Function1( mockObjB );//注意這裡傳入的是mock出來的對象 

  EXPECT_TRUE( rst );
}

把類B的方法Function2 mock之後,UT的重點就可以放在對Function1的其它分支上了。

 

重點:將類A改寫為類模板之後,在生產代碼中,需要使用真正的類B對象來進行模板類的實例化,而在測試代碼中,則需要使用mock出來的類B對象進行模板類的實例化。它們之間的無關的,這與mock接口類的虛函數有著本質的區別。

附:

類模板方法的聲明和定義有以下4種方法,可以酌情使用:
① 薦做法是方法在定義的時候就進行實現(類RefactorA);
②  再者是,聲明在模板類中,實現在模板類外,但要在一個文件中;
③  把方法的實現寫入xxx.inl文件,然後在模板類的結尾使用#include “xxx.inl”;
④  把方法的實現寫入xxx.cpp文件,但在cpp文件的最開始需要將模板類實例化。



總之,為了寫出可UT的代碼,需要時刻牢記“依賴注入”這個原則。
歡迎討論。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved