我需要一个类的模拟实现 - 用于测试目的 - 我想知道我应该如何做到这一点。我可以想到两种一般方式:
我习惯于在Java中使用它的第一种方式,它也很常见(可能因为它们有专用的接口类型)。但我几乎没有在C ++中看到这种界面沉重的设计,因此我很想知道。
第二种方式可能会有效,但我不禁想到它有点难看。有人这样做吗?
如果我遵循第一种方式,我需要一些命名帮助。我有一个音频系统,负责加载声音文件和播放加载的曲目。我正在使用OpenAL,因此我将接口称为“音频”和实现“OpenALAudio”。但是,这意味着所有特定于OpenAL的代码都必须进入该类,这感觉有点限制。另一种方法是将类名“Audio”留下,并为界面找到不同的名称,例如“AudioInterface”或“IAudio”。你会建议哪个,为什么?
答案 0 :(得分:4)
就像我不会在Java中手工创建模拟对象一样,我也不会用C ++手工创作它们。模拟对象不仅仅是存根类,而是执行自动检查的测试工具,例如确保调用某些方法,或者按顺序调用它们等等。我会看一下C ++的各种模拟对象框架。 。 googlemock看起来很有趣,但还有其他人。
关于如何从实现中抽象出控制音频资源的概念,我绝对赞成使用带有通用名称的C ++“接口”(纯虚基类)(例如Audio
)和名为的实现类因为它的特殊之处(例如OpenALAudio
)。我建议你不要在你的班级名称中嵌入“interface”或“I”这个词。将类型或程序化概念嵌入到名称中已经不再流行多年(例如,当您将“界面”提升为完整的“类”时,可以强制进行广泛的重命名。)
开发接口是面向对象的概念,因此适用于C ++。一些关于设计专门针对C ++的最重要的书籍都是关于接口编程(用C ++术语来表示使用纯虚拟基类编程)。例如,Design Patterns和Large Scale C++ Software Design。
答案 1 :(得分:3)
“但是我几乎没有在C ++中看到这种界面繁重的设计”,对于您的信息,我建议您只是简单地看一下微软的COM方式。这种基于C ++的技术都是关于界面沉重的设计。
按界面设计是一种很好的编程方式。如果您习惯了,请继续这样做。
如果您发现自己受限于名称,则最好使用名称空间。 对于接口名称,通常将它们称为ISomething,因此只需将其称为IAudio。
答案 2 :(得分:0)
我认为这很大程度上取决于具体情况和模拟所需的复杂性。我认为理想情况下你会使用原始版本,但是由于复杂的依赖性而希望避免使用原文。然后,在继续开发测试代码时,可能需要复制粘贴标题并注释掉所有内容并根据需要重新启用模拟功能。
我必须承认我没有这方面的实际经验,但在我看来,您在原始代码中的侵扰性越小越好。
答案 3 :(得分:0)
您是否考虑使用模拟框架,例如Hippo Mocks?
class Foo {
private:
IBar *bar;
public:
Foo(IBar *bar);
int a(); //calls IBar::c
};
class IBar {
public:
virtual ~IBar() {}
virtual void b() = 0;
virtual int c(std::string) = 0;
};
void TestAFunctionInFoo() {
MockRepository mocks;
IBar *barMock = mocks.InterfaceMock<IBar>();
Foo *newFoo = new Foo(barMock);
mocks.ExpectCall(barMock, IBar::c).With("hello").Return(42);
newFoo->a();
delete newFoo;
}