Use what I call the Mock Preprocessor - the layout is introduced through the preprocessor seam.
I first posted this concept in this question on Programmers.SE, and by the answers to this I judged that this is not a very well-known template, so I thought I should share it. Itβs hard for me to believe that no one has done anything like this before, but since I could not find it documented, I thought I would share it with the community.
The following are conditional implementations of Ugly and NotAsUgly for example.
DependsOnUgly.hpp
#ifndef _DEPENDS_ON_UGLY_HPP_ #define _DEPENDS_ON_UGLY_HPP_ #include <string> #include "Ugly.hpp" class DependsOnUgly { public: std::string getDescription() { return "Depends on " + Ugly().getName(); } }; #endif
Ugly.hpp
#ifndef _UGLY_HPP_ #define _UGLY_HPP_ struct Ugly { double a, b, ..., z; void extraneousFunction { ... } std::string getName() { return "Ugly"; } }; #endif
There are two main options. The first is that only certain Ugly methods are called by Ugly , and you already want to simulate these methods. Second -
Technique 1: Replace all Ugly behavior used by DependsOnUgly
I call this method the Partial Mock preprocessor , because the layout only implements the necessary parts of the interface of the class that mocks it. Use include guards with the same name as the production class in the header file for the mock class to force the production class to never be defined, but rather a layout. Be sure to include the layout before DependsOnUgly.hpp .
(Note that my test file examples are not self-explanatory, it's just for the sake of simplicity and unit test framework agnostic. The focus is on the directives at the top of the file, not the actual testing method.)
test.cpp
#include <iostream> #include "NotAsUgly.hpp" #include "DependsOnUgly.hpp" int main() { std::cout << DependsOnUgly().getDescription() << std::endl; }
NotAsUgly.hpp
#ifndef _UGLY_HPP_
Technique 2: Replace some Ugly behavior used by DependsOnUgly
I call it Subclassed-in-Place Mock because in this case Ugly is a subclass and the necessary methods are overridden and the rest are still available for use - but the name of the subclass is still Ugly . The define directive is used to rename Ugly to BaseUgly ; it uses the undefined directive and Ugly layout subclasses of BaseUgly . Please note that this may require labeling something in Ugly as virtual, depending on the specific situation.
test.cpp
#include <iostream> #define Ugly BaseUgly #include "Ugly.hpp" #undef Ugly #include "NotAsUgly.hpp" #include "DependsOnUgly.hpp" int main() { std::cout << DependsOnUgly().getDescription() << std::endl; }
NotAsUgly.hpp
#ifndef _UGLY_HPP_
Please note that both of these methods are slightly unreliable and should be used with caution. They should be moved away, since most of the code base is under control and replaced by more standard means of breaking dependencies, if possible. Note that both can potentially be ineffective if the include directives of the legacy codebase are dirty enough. However, I have used them both successfully and for existing legacy systems, so I know that they can work.