如何模拟库调用?

时间:2012-07-27 11:30:49

标签: c++ unit-testing testing

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允许我模拟课程。我不知道如何在我测试的方法中模拟一个调用。

4 个答案:

答案 0 :(得分:4)

所以我假设你有一个'全局'函数,它在一个库中实现,你可以包含一个头文件(用于获取定义)和链接(用于获取实现)。

你显然需要用你自己的库替换库的实现 - 一个“什么都没做”的实现,所以你可以用两种方式来实现:

  • 将.dll(或.so)替换为您自己的实现,该实现具有第三方库公开的所有方法。一旦你编写了所有第三方lib函数的新版本,这很容易,但是将它们全部写完可能会很痛苦。
  • 暂时删除库,并在实现这些功能的.cpp源文件中替换您对该库的调用。因此,您将在.cpp文件中创建自己的sendMail()函数,并将其包含在程序中,而不是包含在mailsender.h中。

后者更容易,但您可能还需要修改程序以不与第三方lib链接。这也可能需要更改#include,因为一些编译器(例如VC ++)允许您在源代码中嵌入链接器指令。如果您这样做,那么您将无法阻止链接器包含第三方库。

另一种选择是修改你的代码以使用对sendMail调用的不同调用,例如你自己实现的test__sendMail()。包装这是一个宏,有条件地包含你的或真正的函数调用,具体取决于你的构建选项。

如果这是一个c ++库,那么你可能会像你习惯的那样使用一个模拟框架,但它听起来像是一个C库,它们只是提供了一个你直接使用的函数列表你的代码。您可以将库包装在您自己的类中,并使用它而不是直接调用第三方lib函数。

There is a list of C mocking frameworks.

答案 1 :(得分:3)

这是一个老问题,已经选择了回复,但也许以下贡献可以帮助其他人。

第一个解决方案

您仍然需要创建一个自定义库来重新定义这些函数,但是您不需要将Makefile更改为链接到您的“假库”,只需使用LD_PRELOAD和伪库的路径,这将是首先,链接器将找到然后使用。

example

第二种解决方案

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..
}

您的程序必须使用与位置无关的代码(使用共享库构建)进行编译才能实现此目的。

此处有更多例子: https://github.com/mollismerx/elfspy/wiki

相关问题