【问题标题】:How to Mock Member Objects in C++如何在 C++ 中模拟成员对象
【发布时间】:2016-02-26 08:18:33
【问题描述】:

我想为我们的项目创建一个单元测试环境。但是我对如何为班级成员创建模拟感到迷茫。我想用一个例子来解释我的问题。

在我以前的项目中,我们使用了一种模拟选择机制,在我看来这很丑陋。这是老方法:

class member {
};

class member_mock_1 {
};

class member_mock_2 {
};

class parent {
#if defined UNIT_TEST_1
  typedef member_t member_mock_1;
#elif defined UNIT_TEST_2
  typedef member_t member_mock_2;
#else
  typedef member_t member;
#endif

private:
  member_t mem;
};

第一个问题是在父类中使用类型定义来模拟成员对象的类是否正确?最佳做法是什么?如果我想使用单元测试框架,比如 gtest,我应该使用这种方式还是有其他方式来模拟成员?

注意1:如果激活了virtual机制,可以创建基类方便mock,如果类是pod什么的,我不想用这个机制。

注 2:我还发现将成员类型作为模板参数传递很丑陋,项目中的一切都变成了模板。我不想那样做。这是一个例子:

template <typename M>
class parent {
private:
  M mem;
};

#if defined UNIT_TEST_1
  typedef parent_t parent<member_mock_1>;
#elif defined UNIT_TEST_2
  typedef parent_t parent<member_mock_2>;
#else
  typedef parent_t parent<member>;
#endif

这是我在这里建议的方法:

member_mock_1.hpp

class member_mock_1 {
};

member_mock_2.hpp

class member_mock_2 {
};

模拟.hpp

template <typename TYPE>
struct mock { using type = TYPE; };

#define ENABLE_MOCKING(NamE) \
using NamE ## _t = mock<NamE>::type

member_mock.hpp

#if define UNIT_TEST_1
  template<>
  struct mock<member> { using type = member_mock_1 };
#endif

#if define UNIT_TEST_2
  template<>
  struct mock<member> { using type = member_mock_2 };
#endif

member.hpp

class member {
};

ENABLE_MOCKING(member);

父级.hpp

class parent {
private:
  member_t mem;
};   

我上面提到的方法适用于普通课程。对于模板类,我认为应该做一些额外的工作。

因此,作为结论,我建议采用上述的单元测试结构。可能没有必要,还有一些其他机制或方法可以满足该要求。也许我还在重新发明轮子:(

请提出一种你知道的嘲弄班级成员的方法。

谢谢。

【问题讨论】:

    标签: c++ unit-testing mocking


    【解决方案1】:

    是的,你在重新发明轮子,代码看起来真的很乱:

    #if defined UNIT_TEST_1
      typedef parent_t parent<member_mock_1>;
    #elif defined UNIT_TEST_2
      typedef parent_t parent<member_mock_2>;
    #else
      typedef parent_t parent<member>;
    #endif
    

    有多种工具可用。 我使用 Typemock Isolator++,因为您可以模拟几乎所有内容而无需接触您的制作。 另一件事是,您在 mock 上设置的行为将仅在测试范围内应用,因此每个测试都有单独且独立的设置。

    您可以访问该成员,即使它是私有的:

    member* mock_member = FAKE<member>;
    parent* my_parent = new parent();
    ISOLATOR_SET_MEMBER(my_parent, mem, mock_member);
    

    轻松搞定:

    member* get_member;
    ISOLATOR_GET_MEMBER(my_parent, mem, get_member);
    

    此外,它还允许伪造抽象类、全局方法、纯虚拟方法、私有和受保护方法,为其设置行为。此外,访问隐藏的数据成员并调用它们。更多信息请查看this

    【讨论】:

      【解决方案2】:

      我的情况与您类似 - 将单元测试引入遗留 C++ 项目。为此,我使用了很多预处理器指令以及Google TestGoogle Mock。特别是,如果我面对你的例子,我会这样做:

      #if defined UNIT_TEST
      class imember
      {
          virtual void a_method() = 0;
      };
      #endif
      
      class member
      #if defined UNIT_TEST
      : public imember
      #endif
      {
          void a_method()
          {
              // do something
          };
      };
      
      class parent {
      public:
      #if defined UNIT_TEST
          parent(imember mem) : mem_(mem) {};
      #endif
      
      private:
      #if defined UNIT_TEST
          imember mem_;
      #else
          member mem_;
      #endif
      };
      

      现在,使用 Google Mock 定义一个模拟类:

      class mockmember : public imember
      {
      public:
          MOCK_METHOD0(a_method, void());
      };
      

      模拟课程现已准备就绪。使用 Google Test 定义您的测试场景:

      class parenttest : public testing::Test
      {
      public:
          parenttest() : member_(mockmember()), parent_(member_) {}
          virtual void SetUp() {}
          virtual void TearDown() {}
      
      protected:
          parent parent_;
          mockmember member_;
      };
      
      TEST_F(parenttest, a_func)
      {
          EXPECT_CALL(member_, a_method());
          int ret = parent_.a_func();
          ASSERT_EQ(0, ret);
      }
      

      【讨论】:

        【解决方案3】:

        免责声明,我在 Typemock 工作。

        山姆完全正确。 此外,您不需要为每个单元测试创​​建 3 个不同的 member_mock 类。

        您可以简单地设置行为,例如,对于成员中的某些私有方法:

        member* mock_member = FAKE<member>;
        PRIVATE_WHEN_CALLED(member, somePrivateMethod()).Return(0);
        

        接下来使用 PRIVATE_WHEN_CALLED(mock_member, somePrivateMethod()) 将重载 somePrivateMethod() 的行为,因此,与其创建大量不同的模拟类,不如根据需要更改行为。

        希望对你有用!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-04-07
          • 1970-01-01
          • 1970-01-01
          • 2010-09-07
          • 2015-12-26
          • 2011-05-08
          • 2011-05-12
          • 1970-01-01
          相关资源
          最近更新 更多