27

To be able to unit test my C++ code I usually pass the constructor of the class under test one or several objects that can be either "production code" or fake/mock objects (let's call these injection objects). I have done this either by

  1. Creating an interface that both the "production code" class and the fake/mock class inherits.
  2. Making the class under test a template class that takes the types of the injection objects as template parameters, and instances of the injection objects as parameters to the constructor.

Some random thoughts:

  • Until we have concepts (C++0x), only documentation and parameter naming will hint what to provide the class under test (when using templates).
  • It is not always possible to create interfaces for legacy code
  • The interface is basically only created to be able to do dependency injection
  • In the same way: templating the class under test is done only to enable dependency injection

What are your thoughts? Are there other solutions to this problem?

Tommy
  • 99,986
  • 12
  • 185
  • 204
Tobias Furuholm
  • 4,727
  • 4
  • 30
  • 39

4 Answers4

11

With C++, there's another option - you give your mock classes exact same names as the real classes, and when linking your unit tests, just link them with mock object/library files instead of real ones.

Pavel Minaev
  • 99,783
  • 25
  • 219
  • 289
  • 3
    In theory yes. But I don't think it would be good in practice. E.g. the class that you want to mock in one test will problably be tested in another test. Then you need to create a separate project (VS project e.g.) for every test suite or something like that... – Tobias Furuholm Jul 14 '09 at 21:14
  • 1
    Pretty much yes. I just have very strong antipathy towards significant code changes (such as interfaces and DI everywhere even when they have no real point) solely to accommodate testing frameworks. In any case, I can tell you that this scheme does work in practice (I've seen it successfully used in production), even though it does require more boilerplate - but at least it's not in the code itself! – Pavel Minaev Jul 14 '09 at 22:40
  • I agree. I will have to do some investigation in what consequences it would have for us. Maybe some magic can be applied to the VS projects to make it easier. – Tobias Furuholm Jul 15 '09 at 14:55
  • This is an interesting approach and strikes me as more "C++-like" than other solutions which either require a performance hit of some kind (however slight) or bloated code. – Rotsiser Mho Aug 19 '13 at 15:10
  • This is called a "stub" i think. – Fantastic Mr Fox Nov 07 '22 at 01:22
7

I think interface option is better, but one doesn't have to create common base class just for test. You can inherit your mock class from production class and override necessary methods. You'll have to make the methods virtual though, but that's how tools like mockpp work and they also allow automate this process a little bit.

Oleg Zhylin
  • 1,290
  • 12
  • 18
  • That's so simple, yet really powerful. I like it! – Tobias Furuholm Jul 15 '09 at 14:48
  • 4
    Just for the record, people should be aware that there are issues with making methods virtual (see Non-Virtual Interface (NVI) idiom) – Tobias Furuholm Aug 29 '09 at 23:10
  • 1
    Yes, sometimes this approach can come in conflict with "puristic NVI". In many cases you can get away with mocking just protected virtual functions, but if you do need to mock public non-virtual interface I suppose it doesn't hurt too much to make it public-virtual and still use NVI. One does lose some compiler-enforcement of the best practice in this case, but not the best practice itself. – Oleg Zhylin Sep 01 '09 at 22:57
  • It is not always possible to (safely) inherit from the production class: for instance, if there are side-effects from the constructor, or if it has data fields which interfere with external things that should be untouched by test code. – Joe F Aug 05 '15 at 00:01
3

Templates will have slightly less performance penalties for runtime (less indirections, less calls, more inline optimizations), but will make you suffer a very high penalty for compilation times...

I think that for this purpose, interfaces are better (until we have concepts in C++0x TR1)... unless if you can't slow down some "bottleneck code". Interfaces are more dynamic and switchable at run-time.

Remember that you can construct your class with default injection objects (the real ones), but you can have factories that inject the mock ones on your tests... you don't even need to subclass.

e.tadeu
  • 5,024
  • 2
  • 20
  • 21
  • 1
    Could you elaborate on the last paragraph? How would you use factories to inject mock objects? – Tobias Furuholm Jul 15 '09 at 14:56
  • 1
    In a short: You can have a singleton factory that creates all your internal needed objects, and you can replace this factory with one that creates mock objects in your tests – e.tadeu Jul 16 '09 at 20:44
3

Don't know if it helps, but you can have template constructors:

struct Class_Under_Test
{
    template <typename Injected>
    Class_Under_Test()
    {
         ...

    // and even specialize them
    template <>
    Class_Under_Test <A_Specific_Injection_Class>
    {
        ...

Only the one that is actually used will get included.

sth
  • 222,467
  • 53
  • 283
  • 367
keraba
  • 554
  • 2
  • 9