0

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

这是我的 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() 系统调用。我怎么能那样做?

4

2 回答 2

3

无法按原样模拟全局函数。相反,您可以添加一个抽象层并将系统调用包装在一个接口中:

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. 您不必在生产代码中更改对接口的任何调用,只需更改注入的类即可。

请注意,这不会在单元测试中运行任何额外的进程,但这是一个优势。您应该单独测试在进程中运行的代码。

于 2019-01-11T14:03:00.237 回答
0

这有点晚了,但您可以重新定义它,并“注入” 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 */
}

PS这种方法有它的缺点。在测试结束时,它会说您的代码泄漏),所以由您来解决这个问题。

于 2020-03-26T19:48:22.807 回答