简体   繁体   English

用C ++实现模拟

[英]Mock implementations in C++

I need a mock implementation of a class - for testing purposes - and I'm wondering how I should best go about doing that. 我需要一个类的模拟实现 - 用于测试目的 - 我想知道我应该如何做到这一点。 I can think of two general ways: 我可以想到两种一般方式:

  1. Create an interface that contains all public functions of the class as pure virtual functions, then create a mock class by deriving from it. 创建一个包含该类的所有公共函数的接口作为纯虚函数,然后通过派生它来创建一个模拟类。
  2. Mark all functions (well, at least all that are to be mocked) as virtual . 将所有函数(至少是所有要模拟的函数)标记为虚拟

I'm used to doing it the first way in Java, and it's quite common too (probably since they have a dedicated interface type). 我习惯于在Java中使用它的第一种方式,它也很常见(可能因为它们有专用的接口类型)。 But I've hardly ever seen such interface-heavy designs in C++, thus I'm wondering. 但是我几乎没有在C ++中看到这种界面沉重的设计,因此我很想知道。

The second way will probably work, but I can't help but think of it as kind of ugly. 第二种方式可能会起作用,但我不禁想到它有点难看。 Is anybody doing that? 有人这样做吗?

If I follow the first way, I need some naming assistance. 如果我按照第一种方式,我需要一些命名帮助。 I have an audio system that is responsible for loading sound files and playing the loaded tracks. 我有一个音频系统,负责加载声音文件和播放加载的曲目。 I'm using OpenAL for that, thus I've called the interface "Audio" and the implementation "OpenALAudio". 我正在使用OpenAL,因此我将接口称为“音频”和实现“OpenALAudio”。 However, this implies that all OpenAL-specific code has to go into that class, which feels kind of limiting. 但是,这意味着所有特定于OpenAL的代码都必须进入该类,这感觉有点限制。 An alternative would be to leave the class' name "Audio" and find a different one for the interface, eg "AudioInterface" or "IAudio". 另一种方法是保留类“名称”Audio“并为界面找到不同的名称,例如”AudioInterface“或”IAudio“。 Which would you suggest, and why? 你会建议哪个,为什么?

Just as I would not hand-author mock objects in Java, I would also not hand-author them in C++. 就像我不会在Java中手工创建模拟对象一样,我也不会用C ++手工创作它们。 Mock objects are not just stubbed out classes, but are test tools that perform automated checks like making sure certain methods are called, or that they are called in order, etc. I would take a look at the various mock object frameworks for C++ out there. 模拟对象不仅仅是存根类,而是执行自动检查的测试工具,例如确保调用某些方法,或者按顺序调用它们等等。我会看一下C ++的各种模拟对象框架。 。 googlemock looks interesting, but there are others. googlemock看起来很有趣,但还有其他的。

Regarding how to abstract out the concept of controlling Audio resources from the implementation, I definitely favor using a C++ "interface" (pure virtual base class) with a generic name (eg Audio ) and an implementation class named for what makes it special (eg OpenALAudio ). 关于如何从实现中抽象出控制音频资源的概念,我绝对赞成使用带有通用名称的C ++“接口”(纯虚拟基类)(例如Audio )和一个以其特殊性命名的实现类(例如OpenALAudio )。 I suggest you not embed the word "interface" or "I" into your class names. 我建议你不要在你的班级名称中嵌入“interface”或“I”这个词。 Embedding type or programmatic concepts into names has been falling out of vogue for many years (and can force widespread renaming when you, for example, elevate an "interface" to a full-fledged "class"). 将类型或程序化概念嵌入到名称中已经不再流行多年(例如,当您将“界面”提升为完整的“类”时,可以强制进行广泛的重命名)。

Developing to interfaces is an object-oriented concept and thus appropriate for C++. 开发接口是面向对象的概念,因此适用于C ++。 Some of the most important books on design specifically targeting C++ are all about programming to interfaces (which in C++ terms means programming using pure virtual base classes). 一些关于设计专门针对C ++的最重要的书籍都是关于接口编程(用C ++术语来表示使用纯虚拟基类编程)。 For example, Design Patterns and Large Scale C++ Software Design . 例如, 设计模式大规模C ++软件设计

"But I've hardly ever seen such interface-heavy designs in C++", for your information, I advise you just take a brief look at the microsoft COM way of doing. “但我几乎没有在C ++中看到这种界面密集的设计”,对于您的信息,我建议您只是简单地看一下微软COM的做法。 This technology, based on C++, is all about interface-heavy design. 这种基于C ++的技术完全是面向接口的设计。

Design by interface is a good way of programming. 通过接口设计是一种很好的编程方式。 If you are used to it, continue this way. 如果你习惯了,继续这样做。

If you find yourself limited with names, it is a good practice to use namespaces. 如果您发现自己受限于名称,则使用名称空间是一种很好的做法。 And for an interface name, it is common to call them ISomething, so just call it IAudio. 对于接口名称,通常将它们称为ISomething,因此只需将其称为IAudio即可。

I'd say that depends a lot on the specific situation and required complexity of the mock. 我会说这很大程度上取决于具体情况和模拟所需的复杂性。 I assume ideally you would use the original, but want to avoid that because of complex dependencies. 我认为理想情况下你会使用原始版本,但是由于复杂的依赖性而希望避免使用原文。 Then it might be worth copy pasting the header and commenting everything out and re-enabling mock functionality as needed as you go on with the development of your testing code. 然后,在继续开发测试代码时,可能需要复制粘贴标题并注释掉所有内容并根据需要重新启用模拟功能。

I must admit I have no practical experience with this, but it seems to me that the less intrusive you can be in your original code the better. 我必须承认我没有这方面的实际经验,但在我看来,你在原始代码中的侵扰性越小越好。

Did you consider using a mock framework, like Hippo Mocks ? 您是否考虑使用像Hippo Mocks这样的模拟框架?

From the wiki : 来自维基

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM