googlemock 如何在测试中使用模拟

googlemock how to use mocking in test

我是 google mock 的初学者,我不确定如何使用它和概念。

如果我正在尝试测试来自 class 的方法,该方法正在调用来自不同 class 的其他方法。 我是否需要从我的测试方法调用的这个不同的 classes 中模拟所有这些方法。 这是一个例子:


class A {
public:
    A () {}
    int setnum(int num) {//do some stuff return 1 or 0//
    }


private:
    int _num;          
};


class B {

  public:
    B (){}
    int init(A *a, int number){ 
     if(a->setnum(number))
        return 1;
     return 0;
     }
    void setNum(int num){_num=num;}

  private:
    A *_a;
    int _num;            
};



class C {
  public:
    int doSoemthing(A *a, int number){ 

    if (domore(a,number))
         return 1;
    return 0;
    }

    int domore(A *a, int number){
        if(_b.init(a,number))
            return 1;
        return 0;

        ;}

  private: 
    B _b;        
};

我是否需要模拟 class A 和 B 中测试我的测试方法所需的所有方法? 或者我可以只模拟一个 Class ,然后测试这个 class 是否有效。

我不是 100% 确定,但在您的示例中,您根本不必使用模拟。您可以在这里非常轻松地创建对象。

当我希望调用某些方法并且应该 return 特定值时,我会使用模拟 - 我不是在测试这个方法,而是例如 if-statement:

 A a;
 if(a.method())
 { 
      // some logic 
 }
  • 为了操纵 if 会得到什么,我会使用这样的模拟:EXPECT_CALL(aMock.method()).WillOnce(Return(true)); 但是您可以在更多情况下使用它(例如:您可以避免创建非常大的 class 并将其替换为模拟对象)。

为了使用模拟测试 C class,您需要为依赖项引入一个接口,而不是在 C class 中使用(此处添加了 BIface)。然后你需要使用 BIface 的依赖注入到 C class (通过添加的构造函数)。有了它,您将能够测试 B 和 C classes 的交互。 IMO A class 不需要在 CTest 中模拟(但很可能需要在 BTest 中进行测试)

class A {
public:
  A() {}                // not needed
  int setnum(int num) { // do some stuff return 1 or 0//
  }

private:
  int _num;
};

class BIface {
public:
  virtual ~BIface() = default;

  virtual int init(A *a, int number) = 0;

  virtual void setNum(int num) = 0;
};

class B : public BIface {

public:
  B() {} // not needed
  int init(A *a, int number) override {
    if (a->setnum(number))
      return 1;
    return 0;
  }
  void setNum(int num) override {
    _num = num;
  }

private:
  A *_a;
  int _num;
};

class C {
public:
  C(BIface &b) : _b{b} {}
  int doSoemthing(A *a, int number) {

    if (domore(a, number))
      return 1;
    return 0;
  }

  int domore(A *a, int number) {
    if (_b.init(a, number))
      return 1;
    return 0;

    ;
  }

private:
  BIface &_b;
};

class BIfaceMock : public BIface {
public:
  MOCK_METHOD2(init, int(A *, int));
  MOCK_METHOD1(setNum, void(int));
};

TEST(CTest, givenDoingMoreWhenInitOfBReturnOneThenReturnOne) {
  // can be done in CTest ctor if more tests are needed to avoid code duplciation
  BIfaceMock bMock{};
  A a{};                 // `a` doesn't need to be mocked in CTest. It shall be mocked in BTest as it is dependency of B class, not C class
  C testedObject{bMock}; // dependency injection of BFace to C

  const auto SOME_INT_PARAM = 42;

  // Eq mather is used to match both &a and SOME_INT_PARAM. This confirms proper parameters were passed to init
  EXPECT_CALL(bMock, init(&a, SOME_INT_PARAM)).WillOnce(Return(1));

  ASSERT_EQ(1, testedObject.domore(&a, SOME_INT_PARAM));
}