如何在 C++ 中使用 GMock 将方法(非虚拟)模拟为 Return 特定值?

How to Mock A Method(non-virtual) To Return Particular Value Using GMock in C++?

我的问题是我想将 Static Non-Virtual 方法模拟为 return true,最终 return假的。

我有静态方法 例如:

class SomeClass{ 
    public:
    static bool SomeClass::DoAction() {
        // do some Actions
    };
};

我想 return 在模拟期间始终为真,但默认情况下 return 为假, 反正有 Mock

我尝试了以下方法来检查 on-call 值并找出它导致错误的原因。

class MockSomeClass : public SomeClass {
public:
    MockSomeClass() {
        ON_CALL(this, DoAction).WillByDefault(testing::Return(true));
    }
    virtual ~MockSomeClass(){};
    MOCK_METHODO(DoAction, bool());

由于Mock是用来离开函数的,有什么方法可以return函数的特定值,或者将return值替换为true并继续使用gmock进行测试和 C++ 中的 gtest。 考虑下面的例子 例如:

  FunctionA(){
      if (SomeClass::DoAction()){
          // do Actions - I wanted to pass the call do the actions.
      } 
  };

这里我想测试if true情况下的动作,有没有什么方法可以在不改变任何底层代码的情况下测试上述方法。

我已经尝试了该方法中存在的不同方法,但我仍然无法获得确切的解决方案。 https://github.com/google/googletest/tree/master/googlemock/docs

  1. 使用默认值

    using ::testing::DefaultValue;
    DefaultValue<bool>::Set(true);
    // call the mock methods
    DefaultValue<bool>::Clear();
    
  2. 使用 Invoke,这不起作用,因为静态方法是非空的。

除了上述方法还有其他解决方法吗

本来想写个评论,但是太长了,所以这里是答案。如果您根本无法更改生产代码,请不要进一步阅读,根本不可能对其进行测试(至少不可能更改对 SomeClass::DoAction() 的调用行为)。如果您可以稍微更改代码,并且希望使其更具可测试性和灵活性,请定义负责调用静态(或全局)函数的接口并将其传递给系统的构造函数。

class SomeClass{ 
public:
    static bool DoAction() {
        std::cout << "Call to SomeClass::DoAction" << std::endl;
        return false;
    };
};

// you absolutely need this, otherwise your code will be strongly dependent on the real SomeClass implementation
class ISomeClassInterface {
public:
    virtual ~ISomeClassInterface() = default;
    virtual bool DoAction() = 0;
};

/*
 * use it in the production
 * you can even make it a default constructor parameter to simplify objects
 * constructions outside testing env
 */
class RealSomeClassInterface: public ISomeClassInterface {
public:
    ~RealSomeClassInterface() override = default;
    bool DoAction() override {
        // call to real SomeClass
        return SomeClass::DoAction();
    }
};

class MockSomeClassInterface: public ISomeClassInterface {
public:
    ~MockSomeClassInterface() override = default;
      MOCK_METHOD0(DoAction, bool());
};

class System {
public:
    System(std::shared_ptr<ISomeClassInterface> interface): interface_(interface) {}
    // let's imagine this is your code that is dependent on the DoAction return value
    bool DoAction() {
        return interface_->DoAction();
    }
private:
    std::shared_ptr<ISomeClassInterface> interface_;
};

TEST(xxx, yyy) {
    auto realInterface = std::make_shared<RealSomeClassInterface>();
    auto mockInterface =  std::make_shared<MockSomeClassInterface>();
    ON_CALL(*mockInterface, DoAction()).WillByDefault(Return(true));
    System systemWithRealInterface(realInterface);
    System systemWithMockInterface(mockInterface);
    std::cout << "System::DoAction returns: " << systemWithRealInterface.DoAction() << std::endl;
    std::cout << "System::DoAction returns: " << systemWithMockInterface.DoAction() << std::endl;
}

测试输出应如下所示:

[ RUN      ] xxx.yyy
Call to SomeClass::DoAction
System::DoAction returns: 0

GMOCK WARNING:
Uninteresting mock function call - taking default action specified at:
whatever.cpp:76:
    Function call: DoAction()
          Returns: true
NOTE: You can safely ignore the above warning unless this call should not happen.  Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call.  See https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md#knowing-when-to-expect for details.

System::DoAction returns: 1
[       OK ] xxx.yyy (0 ms)

您也可以使用 C++ 模板进行破解

    template <class T>
    bool DoAction() { return T::DoAction(); }

但我不喜欢也不推荐这种解决方案。