首页 文章

如何模拟一个方法(非虚拟)在C中使用GMock返回特定值?

提问于
浏览
5

我的问题是我想模拟 Static Non-Virtual 方法返回true,最终返回false .

我有静态方法,例如:

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

我想在模拟期间总是返回true,但默认情况下返回false,无论如何都要模拟

我尝试了以下方法来检查通话值并找出它导致错误 .

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

由于Mock用于保留函数,是否有任何方法可以返回函数的特定值,或者将返回值替换为true并在C中使用gmock和gtest继续测试 . 考虑以下例子:

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

在这里我想测试if的情况下的动作,有没有办法在不改变任何底层代码的情况下测试上述方法 .

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

  • 使用默认值
using ::testing::DefaultValue;
DefaultValue<bool>::Set(true);
// call the mock methods
DefaultValue<bool>::Clear();
  • 使用Invoke,这不起作用,因为静态方法是无效的 .

除上述方法外是否有任何解决方案 .

1 回答

  • 2

    我想写一个评论,但它太长了,所以这就是答案 . 如果您根本无法更改 生产环境 代码,请不要进一步阅读,根本无法对其进行测试(至少不可能改变对 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(); }
    

    但我不喜欢,我不推荐这个解决方案 .

相关问题