【问题标题】:Mocking system calls - is there better way? [duplicate]模拟系统调用 - 有没有更好的方法? [复制]
【发布时间】:2013-11-16 02:26:35
【问题描述】:

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

考虑下面的代码

    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

显然,我们需要模拟系统调用来open

我找到了以下方法:

  1. 正确 - 在设计方面但丑陋的方式。创建接口和实现

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

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

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

这个解决方案很好,但我猜不适用于所有编译器。

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

【问题讨论】:

    标签: c++ unit-testing mocking


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      (1) 示例对模拟不正确,可能是因为您不想澄清自己在做什么,而您的示例没有向我展示什么模拟了什么。模拟实际上是多态性的实际示例使用。人们倾向于将所有东西都包装在包装器函数中,甚至包装器类中

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

      (2) 我不知道

      (3) 绝对表明你知道太多并且在单元测试上花费了太多精力。我始终牢记单元测试毕竟会被丢弃。 您遵循什么开发流程?

      【讨论】:

      • 我们正在转向敏捷
      • 你的问题告诉我你正在使用瀑布模型或为已经制作的软件包做一些升级任务等。但请不要嘲笑遗留代码......代码覆盖率往往是大约 70%-85%,我们不需要更多用于单元测试目的。在您的第一个交付包之后仍然报告了错误或缺陷,并且在下一个交付包中需要您修复。
      • 您的回答很大程度上是基于意见的,并且没有回答原始问题,即使是远程的。
      【解决方案3】:

      您必须对要模拟的内容和要进行单元测试的内容划清界限。 100% 的单元测试覆盖率并不是最终目标。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-08
        • 1970-01-01
        • 2021-07-24
        • 2013-04-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多