2010-09-24 254 views
0

比方說,我有下面的類:優雅的方式

class Foo 
{ 
public: 
    Foo() 
    { 
     Bar(); 
    } 

private: 
    Bar(bool aSendPacket = true) 
    { 
     if (aSendPacket) 
     { 
      // Send packet... 
     } 
    } 
}; 

我寫一個測試工具,它需要創建通過工廠模式的Foo對象(即我沒有實例它直接)。我無法更改任何工廠實例化代碼,因爲這是在我無法訪問的框架中。

由於各種原因,我不希望Bar方法在從測試工具運行時發送數據包。

假設我不能直接調用Bar(消除像使用朋友類這樣的潛在解決方案),使用什麼樣的優雅設計模式來防止運行我的測試工具時發送數據包?我絕對不想用特殊情況污染我的生產代碼。

+0

您是否有權訪問並更改'Foo'? – Chubsdad 2010-09-24 04:54:15

+0

@Chubsdad - 是的,我可以改變'Foo'。 – LeopardSkinPillBoxHat 2010-09-24 04:59:49

+0

將Foo放在Facade的後面,它將轉發除Foo()函數以外的所有函數調用。 – wilx 2010-09-24 05:27:49

回答

2

你想要Bar在普通操作中發送數據包,但不是在測試中。所以你必須有一些代碼,當你在測試過程中調用Bar時運行,即使它是一個空函數。問題在於放在哪裏。

我們看不到if(aSendPacket)循環內部的代碼,但是如果它將其工作委託給其他類,那麼我們可以在那裏進行替換。也就是說,如果循環是

if(aSendPacket) 
{ 
    mPacketHandler.send(); 
} 

使工作由`packetHandler類完成:

// packetHandler.cc 

void packetHandler::send() 
{ 
    // do some things 
    // send the packet 
} 

那麼我們可以做出packetHandler類的「靜音」的版本。 (有人會說它是一個存根或一個模擬類,但似乎somedebate這些術語的定義。)

// version of packetHandler.cc to be used when testing e.g. Foo 

void packetHandler::send() 
{ 
    // do some things 
    // don't actually send the packet 
} 

當測試Foo,編譯這個版本的packetHandler和鏈接。工廠贏得不知道區別。

如果,另一方面,將數據包發送的代碼在Foo闡明瞭,沒有辦法來阻止該Foo類的外部行爲,那麼你必須有Foo.cc一個「測試版」(還有其他的方法,但它們笨拙和危險),最好的方式取決於你的代碼庫的細節。如果只有幾個這樣的「不可測試」功能,那麼最好將Foo::bar(...)本身放在一個源文件中,有兩個版本(對其他特殊方法也是這樣)。如果有很多,那麼值得派生一個特定於測試的工廠類,這將構造例如它覆蓋了Bar。畢竟,這是抽象工廠設計模式的用武之地。

0

我會認爲「棒」作爲一種算法來發送數據,如下一個模板方法

// Automation Strategies 
    class AutomationStrategy{ 
    public: 
     void PreprocessSend(bool &configsend) const {return doPreprocessSend(configsend);} 
     void PostprocessSend() const {return doPostprocessSend();} 

     virtual ~AutomationStrategy(){} 

    private: 
     virtual void doPreprocessSend(bool &configsend) const = 0; 
     virtual void doPostprocessSend() const = 0; 
    }; 

// Default strategy is 'do nothing' 
    class Automation1 : public AutomationStrategy{ 
    public: 
     ~Automation1(){} 
    private: 
     void doPreprocessSend(bool &configsend) const {} 
     void doPostprocessSend() const {} 
    }; 

// This strategy is 'not to send packets' (OP's intent) 
    class Automation2 : public AutomationStrategy{ 
    public: 
     ~Automation2(){} 
    private: 
     void doPreprocessSend(bool &configsend) const { 
      configsend = false; 
     } 
     void doPostprocessSend() const {} 
    }; 

    class Foo{ 
    public: 
     Foo(){ 
      Bar(); 
     } 
    private: 
     // Uses Template Method 
     void Bar(bool aSendPacket = true, AutomationStrategy const &ref = Automation1()) 
     { 
      ref.PreprocessSend(aSendPacket); // Customizable Step1 of the algorithm 
      if (aSendPacket)     // Customizable Step2 of the algorithm 
      { 
       // Send packet... 
      } 
      ref.PostprocessSend();   // Customizable Step3 of the algorithm 
     } 
    }; 

    int main(){} 

如果您不能修改「酒吧」界面,然後配置「富」接受測試自動化策略在它的構造函數中並存儲它(稍後在調用'bar'時稍後使用)

0

它可能是一個過分簡化,但我的第一個傾向是添加某種測試條件對象(實際上是一個變量庫)爲false,然後在你想偏離標準行爲進行測試的代碼中插入鉤子,打開[有效全局測試條件對象變量。無論如何,你將需要做等效邏輯,而其他所有的東西似乎不必要地更復雜,更難以理解對象內部的邏輯流程,或者更可能破壞測試案例中的行爲。如果您可以使用最少量的條件切換位置/變量,那可能是最簡單的解決方案。

我的看法,無論如何。