模拟私人会员数据

时间:2012-11-06 18:12:21

标签: c++ unit-testing


   我正在寻找C ++编码风格的最佳实践,以确保单元测试的简易性。问题来自于尝试为私有数据成员实现模拟类。私有数据成员可以通过类中的几种不同方法访问。到目前为止,我能找到的所有示例都展示了如何编写一个模拟类,而不是如何最好地编写将使用真实对象和模拟对象的代码。

在下面的示例中,我不确定如何从类型MyOtherClass到我的模拟MockMyOtherClass获取mCustom。我怀疑我的方法是错误的,因此问题。

class MyClass {
    MyOtherClass mCustom;
};

[编辑]
我使用了编译器指令并添加了一个新的构造函数。

#ifdef UNIT_TESTING
 #include "mock.h"
#else
  #include "myotherclass.h"
#endif

class MyClass {
        MyOtherClass mCustom;
     public:
        MyClass(MyOtherClass pClass) : mCustom(pClass) {}
};

3 个答案:

答案 0 :(得分:3)

您可以使用一些不同的策略(并根据需要混合使用)。

  1. 如果MyOtherClass提供相当基本的功能并且本身经过了充分测试,那么我通常不会嘲笑它。我只是确保在整个项目上运行单元测试时,MyOtherClass在MyClass之前进行测试。

    class MyClass {
    private:
        MyOtherClass mCustom;
    public:
        //...
    };
    
  2. 您可以模拟MyClass,在实际代码中提供MyOtherClass,在测试代码中提供MyOtherClass的模拟版本。

    template <class T>
    class MyClass_impl {
    private:
        T mCustom;
    public:
        //...
    };
    
    typedef MyClass_impl<MyOtherClass> MyClass; // convenience typedef
    
  3. 您可以在接口类和实现类中拆分MyOtherClass。 MyClass只存储一个指向接口类的指针,并在实例化时获取对实现的引用。

    class MyClass {
    public:
        MyClass(MyOtherClass* aCustom) : mCustom(aCustom) {}
    private:
        MyOtherClass* mCustom;
    public:
        //...
    };
    
  4. 您可以使用标题的搜索路径来玩弄技巧。为此,您需要在单独的目录中创建MyOtherClass的模拟版本。然后,确保对于单元测试,首先搜索此单独目录以查找头文件。这使得首先找到MyOtherClass的模拟版本并覆盖MyOtherClass的真实版本。

答案 1 :(得分:0)

当我之前遇到这个问题时,我将MyClass分成两个类:(1)没有引用MyOtherClass的泛型类,(2)实例化模板参数的实现类MyOtherClass。定义的可见性并不完全相同,但我没有发现它对任何实际目的都很重要。

然后为了测试,我写了类似MyTestOtherClass的内容并相应地实例化了MyClass。可以将任意数量的模拟技术应用于MyTestOtherClass,并且可以为不同的测试目的生成多个类。

答案 2 :(得分:0)

假设使用了 #ifndef 标头保护,一种不需要任何代码重构的 hacky 方法是利用它们,在包含实际标头之前在测试代码中定义标头保护宏.

示例:

MyClass.hpp:

#ifndef MY_CLASS_HPP
#define MY_CLASS_HPP

#include "MyOtherClass.hpp"

class MyClass { MyOtherClass custom; };

#endif

MyOtherClass.hpp:

#ifndef MY_OTHER_CLASS_HPP
#define MY_OTHER_CLASS_HPP

class MyOtherClass {};

#endif

TestCode.cpp:

class MyOtherClass {
    // mocking
};


#define MY_OTHER_CLASS_HPP 
// prevents the #include "MyOtherClass.hpp" in "MyClass.hpp" from doing anything
// while the mock version is used

#include "MyClass.hpp"

// test code 

如果您要测试的代码在 .cpp 文件中,您也可以在测试中只 #include .cpp 文件(并确保不要单独编译它以避免重复定义),让您注入标头保护宏定义。