c++ - 如何在 C++ 中使用 GMock 模拟方法(非虚拟)以返回特定值?

标签 c++ unit-testing googletest googlemock

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

我有静态方法 例如:

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

我想在模拟期间始终返回 true,但默认情况下返回 false, 反正有模拟

我尝试了以下方法来检查 on call 值并发现它导致 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 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 的。

除上述方法外,还有其他解决方法吗?

最佳答案

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

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(); }

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

关于c++ - 如何在 C++ 中使用 GMock 模拟方法(非虚拟)以返回特定值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51388755/

相关文章:

PHP 扩展 : undefined symbol: curl_easy_setopt in Unknown on line 0

c++ - 从 const &parameter 到 &parameter 的无效转换似乎是在胡说八道?

.net - 单元测试可查询

c++ - 无法在 ubuntu 上运行 googletest(链接器错误)

c++ - 在单臂 neon 寄存器中有效地将 8 位数字扩展到 12 位

python - 模拟方法属性 python 抛出 AttributionError

unit-testing - 运行测试后保存单元测试结果

c++ - 为什么用项目编译 gtest 而不是使用 lib

c++ - GoogleTest:CLang 错误编译 ASSERT_FALSE(false)

c++ - 如何将 C++ 命名空间分解为多个文件