我们现在正在公司中引入单元测试,并考虑模拟系统调用的最佳方式。
考虑以下代码
int fd = open(path, O_RDONLY);
if (fd < 0) {
LOG.error() << "cannot load plugin " << path << std::endl;
return ERROR(ERROR_OPENING_PLUGING);
}
// do other stuff
显然,我们需要mock系统调用才能打开
我找到了以下方法:
正确 - 在设计方面但丑陋的方式。创建接口和实现
class ISystem { public: typedef std::auto_ptr<ISystem> Ptr; ISystem() {}; virtual ~ISystem() {}; virtual int open(const char* file, int path) = 0; }; class System : public ISystem { public: System() {}; virtual ~System() {}; virtual int open(const char* file, int path); static ISystem::Ptr Get(); };
并使用它
Common::Error dlopen_signed(ISystem::Ptr& system, const char* path, int flags, void*& ret)
{
int fd = system->open(path, O_RDONLY);
if (fd < 0) {
LOG.error() << "cannot load plugin " << path << std::endl;
return ERROR(ERROR_OPENING_PLUGING);
}
char fd_path[32];
我不喜欢它,因为每个函数都需要多一个参数 - ISystem::Ptr& 系统,这对于所有生产代码都是相同的。
此外,不确定速度(这涉及必须非常快的基本系统调用的额外层)
2) 使用链接接缝 链接器的设计使其更喜欢您的功能版本而不是系统版本。
但这不适用于某些系统调用,例如 open (不确定原因),而且这个解决方案有点 hackish。
3) 使用 --wrap 编译器功能
--wrap symbol 使用符号的包装函数。任何未定义的符号引用都将解析为 __wrap_symbol。对 __real_symbol 的任何未定义引用都将被解析为符号。这可用于为系统函数提供包装器。包装函数应称为 __wrap_symbol。如果它想调用系统函数,它应该调用__real_symbol。这是一个简单的例子:
void *
__wrap_malloc (int c)
{
printf ("malloc called with %ld\n", c);
return __real_malloc (c);
}
这个解决方案很好,但不适用于我猜的所有编译器。
问题是 -您在项目中使用的是哪一个?