模拟系统调用 - 有更好的方法吗?

时间:2013-11-05 09:06:36

标签: c++ unit-testing mocking

我们现在正在公司中引入单元测试,并考虑模拟系统调用的最佳方法。

考虑以下代码

    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

显然,我们需要模拟系统调用打开

我找到了以下方法:

  1. 正确 - 在设计方面但丑陋的方式。创建界面和impl

    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();
    };
    
  2. 并使用它

        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&amp;系统,对于所有生产代码都是一样的。

    此外,不确定速度(这涉及必须非常快的基本系统调用的额外层)

    2)使用链接缝 链接器的设计使其更喜欢您的功能版本而不是系统功能。

    但这对某些系统调用不起作用,例如open(不确定原因),这个解决方案有点hackish。

    3)使用--wrap编译器功能

    - 换行符号 使用符号包装函数。任何未定义的符号引用都将解析为__wrap_symbol。对__real_symbol的任何未定义引用都将解析为符号。这可用于为系统功能提供包装器。包装函数应该被称为__wrap_symbol。如果它想调用系统函数,它应该调用__real_symbol。这是一个简单的例子:

    void *
    __wrap_malloc (int c)
    {
      printf ("malloc called with %ld\n", c);
      return __real_malloc (c);
    } 
    

    这个解决方案很不错,但我认为并不适用于所有编译器。

    问题是 - 您在项目中使用哪一个?

3 个答案:

答案 0 :(得分:1)

你必须画一条线来模拟什么,以及单元测试的内容。 100%的单元测试覆盖率不是最终目标。

如果你真的想模拟systam调用,最好将它们放在包装器中(问题中的第一个选项)。不是一个巨大的包装器,但你应该按功能将它们分成几个包装器。

答案 1 :(得分:0)

系统调用是基础设施 我们使用包装器包裹infra逻辑 还要设计包装器,以便根据上下文可以有许多包装器 我同意“BЈовић”100%的报道不是最终目标 - 平衡它。

答案 2 :(得分:-1)

(1)关于模拟的例子是不正确的,也许是因为你不想澄清你在做什么,你的例子没有告诉我什么模拟。模拟实际上是多态性的实际例证。人们倾向于在包装函数中包装所有内容,然后甚至在包装类中

IParam param=new ParamMock(xxx);
File file(param); // mocked
....
file.open(xxx)

(2)我不知道它

(3)肯定会让你知道太多,并且花费太多精力进行单元测试。我总是记住,单元测试毕竟会被抛弃。 你在追求什么样的开发过程?