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

How to mock fork and execlp system calls in c++ unit test using gmock framework?

本文关键字:fork execlp 系统调用 单元测试 gmock 何使用 框架 模拟 c++      更新时间:2023-10-16

我有现有的C++代码,它使用fork()系统调用创建一个子进程。子进程使用execl()系统调用执行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()和execl()系统调用。我怎么能那样做?

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

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());
}

这允许您选择真实的系统调用或使用依赖注入的mock。由于你没有提供任何代码,我无法帮你。

通常,您会将指针或对注入类的引用传递给应该使用它的类的构造函数,但很少有其他方法更适合您的项目。

另一个优点是,此代码更为开放-关闭:您可以很容易地(嗯,相对容易地)添加例如Windows实现,而无需更改现有代码-您只需提供另一个继承自OsInterface的类。您不必更改生产代码中对接口的任何调用,只需更改注入的类即可。

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

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

附言:这种方法会失败的。在测试结束时,它会说你的代码leaaks),所以这取决于你来解决这个问题。