如何使用gmock框架在c++单元测试中模拟fork和execlp系统调用?

ntjbwcob  于 2023-02-06  发布在  其他
关注(0)|答案(2)|浏览(213)

我有现有的C++代码,它使用fork()系统调用创建一个子进程。并且子进程使用execlp()系统调用执行linux命令。现在我想使用gmock框架测试此代码,代码覆盖率为100%。我搜索了很多,但我没有得到任何完整的证明解决方案。有人能帮助我吗?
这是我的SUT:

int someclass :: os_fork()
{
  pid_t pid = fork();
  if (pid == -1) {
  cout<<"fork() failed with errno" <<errno <<endl;
  return false;
  }

  if (pid == 0 && (execlp("ls", "ls", nullptr) != 0))
  {
  cout<<"child process failed with errno"<<errno<<endl;
  return false;
  }
  int ppid = pid;
  return 0;
}

我想模拟fork()和execlp()系统调用,怎么做呢?

fnatzsnv

fnatzsnv1#

模拟全局函数是不可能的,相反,你可以添加一个抽象层并将系统调用 Package 在一个接口中:

class OsInterface {
    virtual pid_t fork() = 0;
}

class OsInterfaceImpl : public OsInterface {
    virtual pid_t fork() override 
    {
        return ::fork();
    }
}

class OsInterfaceMock : public OsInterface {
    MOCK_METHOD0(fork, pid_t());
}

这允许你选择真实的的系统调用或者用Dependency Injection模拟。因为你没有提供任何代码,我不能帮助你。
通常,您会将指向注入类的指针或引用传递给应该使用它的类的构造函数,但是几乎没有其他方法可以更好地适合您的项目。
另一个优点是该代码更加 * 开放-封闭 *:你可以很容易地(相对容易地)添加Windows实现,而不需要改变现有的代码--你只需要提供另一个继承自OsInterface的类。你不必在你的产品代码中改变任何对接口的调用,只需要改变注入的类。
注意,这不会在单元测试中运行任何额外的进程,但这是一个优点。您应该单独测试在进程中运行的代码。

64jmpszr

64jmpszr2#

现在有点晚了,但是你可以重新定义它,然后“注入”MockFunction来做一些预期。我猜是某种挂钩。

#define CALL_ORIGINAL -2    
testing::MockFunction<int()> forkHelp;

pid_t fork(void)
{
    auto mockResult = forkHelp.Call();
    if (CALL_ORIGINAL != mockResult)
    {
        return mockResult;
    }
    return syscall(SYS_fork); /* Hack for calling real syscall */
}

这种方法有它的缺点。在测试结束时,它会说你的代码泄漏),所以这取决于你的工作。

相关问题