简体   繁体   中英

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). But I've hardly ever seen such interface-heavy designs in C++, thus I'm wondering.

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". However, this implies that all OpenAL-specific code has to go into that class, which feels kind of limiting. An alternative would be to leave the class' name "Audio" and find a different one for the interface, eg "AudioInterface" or "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++. 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. googlemock looks interesting, but there are others.

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 ). I suggest you not embed the word "interface" or "I" into your class names. 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++. 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). For example, Design Patterns and Large Scale C++ Software Design .

"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. This technology, based on C++, is all about interface-heavy design.

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.

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 ?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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