Mocking in C++: the virtual problemPosted: July 18, 2013
Mocking objects is crucial for a good test suite. If you don’t have a way to mock heavy objects you’ll end up with slow and unreliable tests that depend on database status to work. On the other hand, C++ mocking tends to be a bit harder than it is on dynamic languages. A frequent problem people find when mocking are virtual methods.
What’s the problem with virtual methods? C++ has the policy of “not paying for what you don’t use”. That means, not using virtual methods is “cheaper” than using them. Classes with no virtual methods don’t require a virtual dispatch nor a vtable, which speeds things up. So, for a lot of critical objects people will try to avoid virtual methods.
How is this a problem for mocking? A mock is usually a class which inherits from the real class, as a way to get the proper interface and to be compatible with code that uses the real implementation. If a mock inherits from the real thing you’ll need to define all of its methods as virtual, even if you don’t need to, just so you can actually implement a mock.
A possible solution
The problem is clear: we need some methods to behave as virtual, without defining them as virtual.
A solution to this problem, the one I personally choose, is using a TEST_VIRTUAL macro in the definition of each mockeable method for a class; in release builds I just compile with -DTEST_VIRTUAL=””, and for testing builds I compile with -DTEST_VIRTUAL=”virtual”. This method is very simple and works fine but has the (very severe) downside of creating a different release code than the code you test; this might be acceptable, but it’s a risk nonetheless.
Other possible solutions I’ve seen in the past are:
- Making everything virtual, even if not strictly necessary. Quite an ugly solution, in my opinion, it can affect performance and the code is stating that a method can be overridden, even if this don’t make sense.
- Using some kind of CRTP for static dispatching: probably one of the cleanest solutions, but I think it adds too much overhead to the definition of each class.
- Don’t make the mock inherit from the real implementation, make the user code deduce the correct type (eg by using templates). It’s also a clean solution, but you loose a lot of type information (which might or might not be important) and it might also severely impact the build time
To conclude, I don’t think there’s a perfect solution to the virtual problem. Just choose what looks better and accept we live in an imperfect world.