I'm using Google Mock, and I'm struggling to mock out C++ system calls (specifically the C++11 chrono functions).
I'm know I'm supposed to make an interface, create a class to implement the interface for my actual implementation, and then mock out the interface on my tests. I'm trying to write an embedded application, so this level of indirection sounds too expensive for me.
What is the most efficient/performant way to incorporate system calls into Google Mock?
No, you don't need to resort to mocked static classes - that's one of many options.
If you're in an embedded environment where a virtual dispatch is too much overhead, or the compiler/linker optimizer for that architecture does a really bad job, then you can try the following 3 ways to mock the platform calls.
Assume for simplicity that you want to mock a function in the
std::this_thread
namespace, likesleep_for(std::milliseconds)
.Example 0 - Untestable Baseline
Without mocking, let's assume your code looks like this:
You'd use that class like this:
Due to the dependency on the standard library
sleep_for
function, you have a platform dependency that makessome_function
difficult to unit test without actually making an integration test out of it.Example 1 - Testable Using Static Policy
By telling our class to use a specific thread policy using a class template, we can abstract away the platform dependency in unit tests. The policy can either be static or instance - they both remove the need for a virtual dispatch at runtime and they are pretty easy for a compiler/linker to optimize.
In the static policy case, we have one "real" policy that depends on the platform:
We also have a "mock" policy that we can control in unit tests:
The production class that uses the policy takes the policy type as a template parameter and calls into its
sleep_milliseconds
statically:In production code,
testable_class1
is instantiated using the "real" policy:In the unit test,
testable_class1
is instantiated using the "mock" policy:Upsides of this method:
sleep_for
.Downsides of this method:
Example 2 - Testable Using Instance Policy
In the instance policy case, we have one "real" policy that depends on the platform:
We also have a "mock" policy that we can control in unit tests:
The production class that uses the policy takes the policy type as a template parameter, gets an instance of the policy injected in the contructor and calls into its
sleep_milliseconds
:In production code,
testable_class2
is instantiated using the "real" policy:In the unit test,
testable_class2
is instantiated using the "mock" policy:Upsides of this method:
sleep_for
.Downsides of this method:
testable_class2
) - if the interactions don't need verifying, the policy can be passed by value in the constructor and most of the class goo goes away.Example 3 - Testable Using Virtual Policy
This differs from the first 2 examples in the way that this relies on virtual dispatch, but leaves a likely possibility for the compiler/linker to optimize the virtual dispatch away if it can detect that the instance operated on is of base type.
First, we have the production base class that uses the "real" policy in a non-pure virtual function:
Second, we have the derived class that implements a "mock" policy in the virtual function (a kind of Template Method design pattern):
In production code,
testable_class3
is just instantiated as itself:In the unit test,
testable_class3
is instantiated using the "mock" derived class:Upsides of this method:
sleep_for
.Downsides of this method:
final
(C++11), since it must be allowed to be inherited from, and this might affect the rest of the class design if there is more complexity than the simple example above.Test Run
All of the above can be tested with this:
and the complete runnable example is at http://pastebin.com/0qJaQVcD
First of all, virtual dispatch is not that expensive, therefore you may be doing micro optimization. Even for an embedded platform.
If you really want to avoid virtual dispatch, you could use static polymorphism, with templates, and inject system calls through template parameter. Something like this :
Above all, try to avoid singletons. They are just hidden global variables.