【问题标题】:How to Mock A Method(non-virtual) To Return Particular Value Using GMock in C++?如何在 C++ 中使用 GMock 模拟方法(非虚拟)以返回特定值?
【发布时间】:2018-12-25 14:10:58
【问题描述】:

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

我有静态方法 例如:

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

我想在模拟期间始终返回 true,但默认情况下返回 false, 反正有什么可以模拟的吗

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

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 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,这不起作用,因为静态方法是非 void。

除了上面提到的方法之外,有没有其他解决方案。

【问题讨论】:

  • 我发现了这个:testing.googleblog.com/2008/12/…
  • 我的问题无法解决,因为我需要在不编辑实际代码的情况下进行测试。
  • 不能改代码吗?如果可以,您可以制作FunctionA: template &lt;typename T&gt; FunctionA { if(T::DoAction()) {...}} 的模板。然后在您的生产代码中您将传递SomeClass 作为模板参数,在您的测试代码中您将传递MockSomeClass。这不是一个好方法,但我想不出其他方法。

标签: c++ unit-testing googletest googlemock


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-27
    • 2012-07-29
    相关资源
    最近更新 更多