cpp(Java guy)的新手。
我的第三方库有方法sendMail(txt)。 我不想测试库。我想测试我自己的方法,所以为了做到这一点,我需要模拟库调用。
我自己的方法看起来像这样:
#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允许我模拟课程。我不知道如何在我测试的方法中模拟一个调用。
答案 0 :(得分:4)
所以我假设你有一个'全局'函数,它在一个库中实现,你可以包含一个头文件(用于获取定义)和链接(用于获取实现)。
你显然需要用你自己的库替换库的实现 - 一个“什么都没做”的实现,所以你可以用两种方式来实现:
后者更容易,但您可能还需要修改程序以不与第三方lib链接。这也可能需要更改#include,因为一些编译器(例如VC ++)允许您在源代码中嵌入链接器指令。如果您这样做,那么您将无法阻止链接器包含第三方库。
另一种选择是修改你的代码以使用对sendMail调用的不同调用,例如你自己实现的test__sendMail()。包装这是一个宏,有条件地包含你的或真正的函数调用,具体取决于你的构建选项。
如果这是一个c ++库,那么你可能会像你习惯的那样使用一个模拟框架,但它听起来像是一个C库,它们只是提供了一个你直接使用的函数列表你的代码。您可以将库包装在您自己的类中,并使用它而不是直接调用第三方lib函数。
答案 1 :(得分:3)
这是一个老问题,已经选择了回复,但也许以下贡献可以帮助其他人。
您仍然需要创建一个自定义库来重新定义这些函数,但是您不需要将Makefile更改为链接到您的“假库”,只需使用LD_PRELOAD和伪库的路径,这将是首先,链接器将找到然后使用。
ld (GNU) linker有一个选项--wrap ,可以将仅包含一个功能与用户提供的另一个功能。这样您就不必创建新的库/类来模拟行为
以下是手册页
中的示例- 涡卷=符号 使用符号包装函数。任何未定义的符号引用都将解析为“__wrap_ symbol”。任何未定义的引用 将“__real_ symbol”解析为符号。
这可用于为系统功能提供包装器。包装函数应该被称为“__wrap_ symbol”。如果它愿意 调用系统函数,它应该调用“__real_ symbol”。
这是一个简单的例子:
void * __wrap_malloc (size_t c) { printf ("malloc called with %zu\n", c); return __real_malloc (c); }
如果使用--wrap malloc将其他代码与此文件链接,则对“malloc”的所有调用都将调用函数“__wrap_malloc”。 “__wrap_malloc”中对“__real_malloc”的调用将调用真实的 “malloc”功能。
您可能也希望提供“__real_malloc”功能,这样没有--wrap选项的链接就会成功。如果你这样做,你 不应该将“__real_malloc”的定义放在同一个文件中 “--wrap malloc中调用”;如果你这样做,汇编程序可能会解决之前的呼叫 链接器有机会将其包装到“malloc”。
答案 2 :(得分:0)
虽然没有interface
关键字,但您可以在C ++中使用抽象基类来实现类似的东西。
如果您使用的库没有带有这样的抽象,您可以将它包装在您自己的“界面”之后。如果你的代码将对象的构造与使用分开(例如通过IoC),你可以使用它来注入假冒或使用Mocks:
https://stackoverflow.com/questions/38493/are-there-any-good-c-mock-object-frameworks
答案 3 :(得分:0)
免责声明:我写过ELFspy。
使用ELFspy,以下代码将允许您通过将替换为替代实现来伪造/模拟sendMail函数。
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..
}
您的程序必须使用与位置无关的代码(使用共享库构建)进行编译才能实现此目的。