【问题标题】:Method and mock with same class方法和模拟具有相同的类
【发布时间】:2011-06-05 15:42:12
【问题描述】:

我有 2 种方法的课程

class A
{
  void Fun()
  {
    if(FunRet()>0){///} else {///}
  } 
  int FunRet()
  { return 4;}
};

我想测试 Fun() 方法取决于 FunRet 返回的内容。所以我想模拟 FunRet。 我宁愿不想让 FunRet 成为虚拟的。我该怎么做?

【问题讨论】:

    标签: googletest googlemock gmock


    【解决方案1】:

    您可以注入类内依赖项。在这种情况下,让 Fun 接受一个值而不是计算它:

    class A
    {
      void Fun(int x)
      {
        if(x>0){///} else {///}
      } 
      int FunRet()
      { return 4;}
    };
    

    然后您的测试可以将任意值传递给 Fun()。如果您需要强制正确使用,请编写一个公开版本以在您的 API 中公开,并编写一个私有版本进行测试:

    class A {
     public:
      void Fun() { return Fun(FunRet()); }
     private:
      void Fun(int x);  // for testing.
    };
    

    【讨论】:

      【解决方案2】:

      您可以将 Fun 方法提取到实现接口的计算器类中。您应该在构造函数中将该接口的一个实例传递给类 A。

      在测试中,您可以让其他类实现该接口,并返回其他值。

      这种方法还有一个很大的优势,就是你可以将计算值和使用计算值的关注点分开。

      class A {
      public:
         A (IFunCalc calc) { m_calc = calc; }
         void Fun { if calc.FunRet() > 4 ... }
      private:
         IFunCalc m_calc;
      }
      class FunCalc : IFunCulc {
      public:
         int FunRet { return 4; }
      }
      class FunCalc4Test : IFunCalc {
      public:
         int FunRet { return 27; }
      }
      

      【讨论】:

        【解决方案3】:

        我认为您缺少 this 指针。

        ... if ( this->FunRet() > 0 ) { ...

        【讨论】:

          【解决方案4】:

          如果您使用依赖注入并模板化您的被测对象,您可以使用模拟对象而无需使用虚函数。

          class AParameters
          {
          public:
            int FunRet()
            { return 4;}
          };
          
          class MockAParameters
          {
          public:
            MOCK_METHOD0(FunRet, int());
          };
          
          template<class Parameters>
          class AImpl
          {
          public:
             AImpl(Parameters& parameters):parameters(parameters){}
          
            void Fun()
            {
              if(parameters.FunRet()>0){///} else {///}
            } 
          
          private:
             Parameters& parameters;
          };
          
          typedef AImpl<AParameters> A;
          typedef AImpl<MockAParameters> ATestObject;
          
          void Test::funUsesFunRet()
          {
              MockAParameters params;
              EXPECT_CALL(params, FunRet());
              ATestObject object(params);
              object.Fun();
          }
          

          【讨论】:

            【解决方案5】:

            我相信FunRetFun 的内部实现细节。因此,Fun 不需要与FunRet 隔离测试。只需测试Fun,不用担心它调用FunRet

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2020-03-20
              • 2020-01-07
              • 1970-01-01
              • 2023-02-23
              • 1970-01-01
              • 2020-03-20
              • 1970-01-01
              • 2011-10-25
              相关资源
              最近更新 更多