How to mock library calls?
cpp的新手(Java家伙)。
我有第三方库,有方法sendMail(txt)。
我不想测试库。 我想测试我自己的方法,所以为了做到这一点,我需要模拟库调用。
我自己的方法看起来像这样:
1 2 3 4 5 6 7 8 9 | #include"mailsender.h" int run(txt){ analysis(txt); ... ... int status = sendMail(txt);//sendMail is a 3rd party library call. i need to mock it.its not part of the unit test return status; } |
在Java中,mailsender是接口,它被注入我的类,所以在测试的情况下我注入mock。
在模拟库调用的cpp中有什么好的做法?
我可以在一个类中包装第三方库调用并注入这个类,但我正在寻找更简单的东西和常见的实践(也许是ifndf)。
我熟悉googlemock。
googlemock允许我模拟课程。 我不知道如何在我测试的方法中模拟一个调用。
所以我假设你有一个'全局'函数,它在一个库中实现,你可以包含一个头文件(用于获取定义)和链接(用于获取实现)。
你显然需要用自己的库替换库的实现 - 一个"什么都没做",所以你可以通过两种方式来实现:
- 您将.dll(或.so)替换为您自己的实现,该实现具有第三方库公开的所有方法。一旦你编写了所有第三方lib函数的新版本,这很容易,但将它们全部写出来可能会很痛苦。
- 您暂时删除库,并将实现这些功能的.cpp源文件中的调用替换为库。所以你要在.cpp文件中创建自己的sendMail()函数,并将其包含在程序中而不是mailsender.h include中。
后者更容易,但您可能还需要修改程序以不与第三方库链接。这也可能需要更改#include,因为一些编译器(例如VC ++)允许您在源代码中嵌入链接器指令。如果您这样做,那么您将无法阻止链接器包含第三方库。
另一种选择是修改您的代码以使用对sendMail调用的不同调用,例如您自己实现的test__sendMail()。包装这是一个宏,有条件地包含您的或实际的函数调用,具体取决于您的构建选项。
如果这是一个c ++库,那么你可能可以使用像你习惯的模拟框架,但它听起来像是一个C库,它们只是提供了一个直接在代码中使用的函数列表。您可以将库包装在您自己的类中并使用它而不是直接调用第三方lib函数。
有一个C模拟框架列表。
这是一个老问题,已经选择了响应,但也许以下贡献可以帮助其他人。
第一解决方案
您仍然需要创建一个自定义库来重新定义函数,但是您不需要将Makefile更改为链接到您的"假库",只需使用LD_PRELOAD和伪库的路径,这将是第一个链接器将找到然后使用。
例
二解决方案
ld(GNU)链接器有一个选项--wrap,它允许您只使用用户提供的另一个函数包装一个函数。这样您就不必创建新的库/类来模拟行为
以下是手册页中的示例
--wrap=symbol
Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to"__wrap_ symbol". Any undefined reference
to"__real_ symbol" will be resolved to symbol.This can be used to provide a wrapper for a system function. The wrapper function should be called"__wrap_ symbol". If it wishes to
call the system function, it should call"__real_ symbol".Here is a trivial example:
1
2
3
4
5
6
7 void *
__wrap_malloc (size_t c)
{
printf ("malloc called with %zu
", c);
return __real_malloc (c);
}If you link other code with this file using --wrap malloc, then all calls to"malloc" will call the function"__wrap_malloc" instead.
The call to"__real_malloc" in"__wrap_malloc" will call the real
"malloc" function.You may wish to provide a"__real_malloc" function as well, so that links without the --wrap option will succeed. If you do this, you
should not put the definition of"__real_malloc" in the same file as
"__wrap_malloc"; if you do, the assembler may resolve the call before
the linker has a chance to wrap it to"malloc".
免责声明:我写过ELFspy。
使用ELFspy,以下代码将允许您通过将替换为替代实现来伪造/模拟sendMail函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 | void yourSendMail(const char* txt) // ensure same signature as sendMail { // your mocking code } int main(int argc, char** argv) { spy::initialise(argc, argv); auto sendMail_hook = SPY(&sendMail); // grab a hook to sendMail // use hook to reroute all program calls to sendMail to yourSendMail auto sendMail_fake = spy::fake(sendMail_hook, &yourSendMail); // call run here.. } |
您的程序必须使用与位置无关的代码(使用共享库构建)进行编译才能实现此目的。
进一步的例子在这里:
https://github.com/mollismerx/elfspy/wiki
虽然没有
如果您使用的库没有这样的抽象,您可以将它包装在您自己的"界面"后面。如果您的代码将对象的构造与使用分开(例如通过IoC),您可以使用它来注入假的或使用Mocks:
https://stackoverflow.com/questions/38493/are-there-any-good-c-mock-object-frameworks