伪造/模拟非虚拟 C++ 方法
众所周知,在 C++ 中模拟/伪造用于测试的非虚拟方法是困难的.例如,googlemock的cookbook有两个建议――都意味着修改原始源代码以某种方式(作为接口模板和重写).
It known that in C++ mocking/faking nonvirtual methods for testing is hard. For example, cookbook of googlemock has two suggestion - both mean to modify original source code in some way (templating and rewriting as interface).
对于 C++ 代码来说,这似乎是一个非常糟糕的问题.如果无法修改需要伪造/模拟的原始代码,如何才能做到最好?复制整个代码/类(用它整个基类层次结构??)
It appear this is very bad problem for C++ code. How can be done best if you can't modify original code that needs to be faked/mocked? Duplicating whole code/class (with it whole base class hierarchy??)
推荐答案
我按照Link Seam 链接来自 sdg 的答案.在那里我读到了不同类型的接缝,但预处理接缝给我留下了最深刻的印象.这让我考虑进一步利用预处理器.事实证明,可以在不实际更改调用代码的情况下模拟任何外部依赖项.
I followed the Link Seam link from sdg's answer. There I read about different types of seams, but I was most impressed by Preprocessing Seams. This made me think about exploiting further the preprocessor. It turned out that it is possible to mock any external dependency without actually changing the calling code.
为此,您必须使用替代依赖定义来编译调用源文件.这是一个示例.
To do this, you have to compile the calling source file with a substitute dependency definition. Here is an example how to do it.
依赖.h
#ifndef DEPENDENCY_H
#define DEPENDENCY_H
class Dependency
{
public:
//...
int foo();
//...
};
#endif // DEPENDENCY_H
调用者.cpp
#include "dependency.h"
int bar(Dependency& dependency)
{
return dependency.foo() * 2;
}
test.cpp
#include <assert.h>
// block original definition
#define DEPENDENCY_H
// substitute definition
class Dependency
{
public:
int foo() { return 21; }
};
// include code under test
#include "caller.cpp"
// the test
void test_bar()
{
Dependency mockDependency;
int r = bar(mockDependency);
assert(r == 42);
}
请注意,mock 不需要实现完整的 Dependency
,只需实现最小的(由 caller.cpp 使用),以便测试可以编译和执行.通过这种方式,您可以模拟非虚拟、静态、全局函数或几乎任何依赖项,而无需更改生产代码.我喜欢这种方法的另一个原因是与测试相关的所有内容都在一个地方.您不必到处调整编译器和链接器配置.
Notice that the mock does not need to implement complete Dependency
, just the minimum (used by caller.cpp) so the test can compile and execute.
This way you can mock non-virtual, static, global functions or almost any dependency without changing the productive code.
Another reason I like this approach is that everything related to the test is in one place. You don't have to tweak compiler and linker configurations here and there.
我已经成功地将这种技术应用于一个具有大量依赖项的现实世界项目中.我在 Include mock 中更详细地描述了它.
I have applied this technique successfully on a real world project with big fat dependencies. I have described it in more detail in Include mock.
相关文章