1

I'm currently working on my first project that uses TDD and unit testing. I'm writing in C++ with googletest and googlemock libraries. The project requires many small classes with particular functionalities. I mostly use dependency injection in constructors. According to this:

When should I mock? and When to use mock objects in unit tests

dependency injected into constructor is good candidate for mocking in unit testing. There are two ways to do this in C++:

  1. Creating interface (pure virtual class). Production class and mock class derives from it.
  2. Create virtual member functions inside Production class. Mock class derives from Production class. There is a problem when Production class does not define default constructor. Mock class has to call Base class constructor explicitly (personally it is not the stuff that mock object should do).

How do you handle this kind of situation? Do you prefer many interfaces (N classes requires N interfaces) or deriving from Base class?

Marko Popovic
  • 3,999
  • 3
  • 22
  • 37
Mati
  • 753
  • 4
  • 20
  • 1
    Why have you tagged Java? And for my two cents, in java using `Mockito.mock()` you can directly mock `classes` by using a cglib proxy, but I am unsure how that works with c++ – Lino Jul 10 '20 at 07:39
  • @Mati Since there were no other answers in more than a year, and my answer received positive feedback, please consider marking it as an accepted answer. – Marko Popovic Oct 28 '21 at 09:36

1 Answers1

3

There is no single best answer to a question like this, but I can share some experience from my team. The approach we use is the following. The project is split into something we internally call "modules". These are basically just C++ classes, but what is special about them is that those are the biggest/most important classes in the project. Interfaces of these classes are exposed to other modules (this is configured via CMake) so they can be used with one another. Each module is a small static library, and inside that library there are additional C++ classes that are necessary only to complete the functionality of the containing module, but are irrelevant to other modules. These are configured to be private withing the module (again via CMake) and other modules have no knowledge of these classes.

So after a short explanation of how our project is organized, getting back to your question:

  1. For the main classes of the module (usually 1-3) that need to be exposed to other modules, we create an interface (pure virtual class) with detailed documentation (precise contract detailing how the client should use the class, sequence diagrams, detailed documentation for all methods, etc.). Then we have a mock that inherits from this interface and it is exposed to other modules, and an implementation class (what you call Production class) that also inherits but is private withing the module (other classes don't need the implementation details, only knowledge how to create and use an instance of the interface).

  2. For other classes that are private within each module, we just create virtual methods inside Production class to keep things simpler, and their mocks just inherit from the Production class. By the way, your issue with the default constructor should easily be solved by declaring a protected default constructor in the Production class?

In my opinion, this provides a good balance between avoiding too much boilerplate code (by having an interface for every single class), but also providing nice, clean and precisely defined interfaces for the most important classes in your project.

Marko Popovic
  • 3,999
  • 3
  • 22
  • 37
  • Thanks! Your approach is very suitable. You said that protected constructor in base class will solve the problems. Yes, but consider that Production does not have default public constructor and protected default construtor must initialize private members. What do you use in this case? Dummy values? – Mati Jul 10 '20 at 15:06
  • @Marko Popovic neat approach. What about private implementation, how do you test it? Are all symbols from these small static libraries accessible in unit tests, or do you only test the public interface? – Quarra Jul 16 '20 at 06:06
  • @Mati Sorry for late reply. Yes, we use dummy/fake values. I don't remember we had issues with this approach. – Marko Popovic Jul 19 '20 at 15:37
  • @Quarra Yes, all symbols are accessible in the tests and we also write tests for these private classes because those classes are often quite complex themselves. There are a few places where the tests were not done because the class is quite simple, but we are trying to avoid doing that as much as possible. – Marko Popovic Jul 19 '20 at 15:48