我正在寻找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) {}
};
答案 0 :(得分:3)
您可以使用一些不同的策略(并根据需要混合使用)。
如果MyOtherClass提供相当基本的功能并且本身经过了充分测试,那么我通常不会嘲笑它。我只是确保在整个项目上运行单元测试时,MyOtherClass在MyClass之前进行测试。
class MyClass {
private:
MyOtherClass mCustom;
public:
//...
};
您可以模拟MyClass,在实际代码中提供MyOtherClass,在测试代码中提供MyOtherClass的模拟版本。
template <class T>
class MyClass_impl {
private:
T mCustom;
public:
//...
};
typedef MyClass_impl<MyOtherClass> MyClass; // convenience typedef
您可以在接口类和实现类中拆分MyOtherClass。 MyClass只存储一个指向接口类的指针,并在实例化时获取对实现的引用。
class MyClass {
public:
MyClass(MyOtherClass* aCustom) : mCustom(aCustom) {}
private:
MyOtherClass* mCustom;
public:
//...
};
您可以使用标题的搜索路径来玩弄技巧。为此,您需要在单独的目录中创建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 文件(并确保不要单独编译它以避免重复定义),让您注入标头保护宏定义。