优雅的方式
比方说,我有下面的类:优雅的方式
class Foo
{
public:
Foo()
{
Bar();
}
private:
Bar(bool aSendPacket = true)
{
if (aSendPacket)
{
// Send packet...
}
}
};
我写一个测试工具,它需要创建通过工厂模式的Foo
对象(即我没有实例它直接)。我无法更改任何工厂实例化代码,因为这是在我无法访问的框架中。
由于各种原因,我不希望Bar
方法在从测试工具运行时发送数据包。
假设我不能直接调用Bar
(消除像使用朋友类这样的潜在解决方案),使用什么样的优雅设计模式来防止运行我的测试工具时发送数据包?我绝对不想用特殊情况污染我的生产代码。
你想要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
。毕竟,这是抽象工厂设计模式的用武之地。
我会认为“棒”作为一种算法来发送数据,如下一个模板方法
// 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'时稍后使用)
它可能是一个过分简化,但我的第一个倾向是添加某种测试条件对象(实际上是一个变量库)为false,然后在你想偏离标准行为进行测试的代码中插入钩子,打开[有效全局测试条件对象变量。无论如何,你将需要做等效逻辑,而其他所有的东西似乎不必要地更复杂,更难以理解对象内部的逻辑流程,或者更可能破坏测试案例中的行为。如果您可以使用最少量的条件切换位置/变量,那可能是最简单的解决方案。
我的看法,无论如何。
您是否有权访问并更改'Foo'? – Chubsdad 2010-09-24 04:54:15
@Chubsdad - 是的,我可以改变'Foo'。 – LeopardSkinPillBoxHat 2010-09-24 04:59:49
将Foo放在Facade的后面,它将转发除Foo()函数以外的所有函数调用。 – wilx 2010-09-24 05:27:49