2010-09-24 214 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,然后在你想偏离标准行为进行测试的代码中插入钩子,打开[有效全局测试条件对象变量。无论如何,你将需要做等效逻辑,而其他所有的东西似乎不必要地更复杂,更难以理解对象内部的逻辑流程,或者更可能破坏测试案例中的行为。如果您可以使用最少量的条件切换位置/变量,那可能是最简单的解决方案。

我的看法,无论如何。