4


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

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

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) {}
};
4

3 回答 3

4

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

  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 的真实版本。

于 2012-11-06T18:51:46.467 回答
0

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

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

于 2012-11-06T18:16:13.513 回答
0

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

例子:

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

测试代码.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 文件(并确保不要单独编译以避免重复定义),以便注入标头保护宏定义。

于 2021-02-15T23:35:56.720 回答