Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 覆盖测试线束中默认代码的优雅方式_C++_Unit Testing_Design Patterns - Fatal编程技术网

C++ 覆盖测试线束中默认代码的优雅方式

C++ 覆盖测试线束中默认代码的优雅方式,c++,unit-testing,design-patterns,C++,Unit Testing,Design Patterns,假设我有以下课程: class Foo { public: Foo() { Bar(); } private: Bar(bool aSendPacket = true) { if (aSendPacket) { // Send packet... } } }; 我正在编写一个测试工具,它需要通过工厂模式创建一个Foo对象(即,我没有直接实例化它)。我无法更改

假设我有以下课程:

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

private:
    Bar(bool aSendPacket = true)
    {
        if (aSendPacket)
        {
            // Send packet...
        }
    }
};
我正在编写一个测试工具,它需要通过工厂模式创建一个
Foo
对象(即,我没有直接实例化它)。我无法更改任何工厂实例化代码,因为这是在我无权访问的框架中

出于各种原因,我不希望从测试线束运行
Bar
方法时发送数据包


假设我不能直接调用
Bar
(消除像使用friend类这样的潜在解决方案),那么在运行测试工具时,使用什么优雅的设计模式来防止数据包被发送出去呢?我绝对不想因为特殊情况而污染我的生产代码。

我将“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”接口,那么将“Foo”配置为在其构造函数中接受测试自动化策略并将其存储(稍后在调用“bar”时使用)

这可能过于简单化,但我的第一个倾向是添加某种类型的测试条件对象(实际上是一个变量库)它将所有内容默认为false,然后将钩子放在代码中希望偏离标准测试行为的地方,打开[有效全局]测试条件对象变量。无论如何,您都需要执行等效的逻辑,而其他一切似乎都不必要地更加复杂,对理解对象内部的逻辑流更具破坏性,或者对测试用例中的行为更具潜在破坏性。如果您可以使用最少数量的条件开关位置/变量,那么这可能是最简单的解决方案


无论如何,我的意见是。

您希望
Bar
在普通操作中发送数据包,而不是在测试中。因此,即使是空函数,在测试期间调用
Bar
时也必须有一些代码运行。问题是把它放在哪里

我们看不到
if(aSendPacket)
循环中的代码,但是如果它将其工作委托给其他类,那么我们可以在那里进行替换。也就是说,如果循环是

if(aSendPacket)
{
  mPacketHandler.send();
}
因此,工作由` packetHandler类完成:

// packetHandler.cc

void packetHandler::send()
{
  // do some things
  // send the packet
}
然后我们可以创建
packetHandler
类的“静音”版本。(有些人会称之为存根或模拟类,但关于这些术语的定义似乎存在一些争论。)

测试
Foo
时,编译此版本的
packetHandler
,并将其链接到。工厂不会知道有什么区别


另一方面,如果发送数据包的代码在
Foo
中详细说明,无法阻止
Foo
类之外的行为,那么您将不得不拥有一个
Foo.cc
的“测试”版本(还有其他方法,但它们既笨拙又危险),最好的方法取决于代码库的细节。如果只有两个这样的“不稳定”特性,那么最好将
Foo::bar(…)
单独放在一个源文件中,有两个版本(并对其他每个特殊方法执行相同的操作)。如果有很多,那么可能值得派生一个特定于测试的工厂类,该类将构造的实例,例如,
类testingFoo:public Foo
,它覆盖
。毕竟,这就是抽象工厂设计模式的用途。

您有权访问并可以更改“Foo”吗?@Chubsdad-是的,我绝对可以更改
Foo
。将Foo放在facade后面,它将向Foo转发除Bar()函数外的所有函数调用。
// version of packetHandler.cc to be used when testing e.g. Foo

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