GTest:模拟非虚拟成员函数

GTest: mocking non-virtual member function

考虑以下代码片段:

source.hpp

class tracker
{
public:
  static tracker& get_instance()
  {
    static tracker instance;
    return instance;
  }

  tracker(const tracker&) = delete;
  tracker& operator=(const tracker&) = delete;

private:
  tracker()
  {
     _ip_count = settings::get_instance().get_ips();
     // ...
  }

private:
  int _ip_count;
};

test.cpp

#include "source.hpp"
#include "settings.hpp"

#include "gtest/gtest.h"
#include "gmock/gmock.h"

struct MockSettings
{
  MOCK_CONST_METHOD0(get_ips, int());
};

TEST(tracker, _)
{
  // Need to mock settings::get_instance().get_ips() function here
  tracker& inst = tracker::get_instance();
}

int main(int argc, char** argv)
{
  ::testing::InitGoogleMock(&argc, argv);
  return RUN_ALL_TESTS();
}

正如您在 test.cpp 中看到的那样,我正在获取 tracker 的实例,因此调用了 settings::get_instance().get_ips() 函数。实际上,我不需要调用后一个函数,相反,我想 return,例如 3。考虑到 get_ips() 非虚拟 函数,我该怎么做。如果可能的话,我不想更改源代码。我还阅读了以下文档https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md,但无法达到我想要的结果。

看来你可能遇到的问题是你试图模拟 class settings,但是跟踪器的构造函数实际上没有办法 使用你的模拟设置class,因为它在编译时被固定为直接引用settings

食谱确实在“Mocking Nonvirtual Methods”下解释了如何解决这个问题:首先,你制作你的模拟 class,然后你提供一些 依赖注入的方法 允许您在编译时在 class 的生产版本和模拟版本之间 select。一种方法是使跟踪器成为一个 class 模板参数化设置 class 类似:

template <typename settings_class> class tracker_template
{
public:
  static tracker_template<settings_class>& get_instance()
  {
    static tracker_template<settings_class> instance;
    return instance;
  }

// ...

private:
  tracker_template()
  {
     _ip_count = settings_class::get_instance().get_ips();
     // ...
  }

// ...
};

之后你可以,例如。 using tracker = tracker_template<settings>; 继续在您的生产代码中使用跟踪器,而不是在您的测试代码中使用 tracker_template<MockSettings>

可能没有办法在不更改代码的情况下解决这个问题。