GTest:模拟非虚拟成员函数

时间:2019-03-07 13:28:10

标签: c++ mocking googletest

请考虑以下代码段:

  

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()函数。实际上,我不需要调用后一个函数,相反,我想返回例如3。考虑到get_ips()非虚拟函数,我该怎么做。如果可能的话,我不想更改源代码。我也阅读了以下文档https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md,但无法达到我想要的结果。

1 个答案:

答案 0 :(得分:1)

您似乎在这里遇到的问题是,您正在尝试模拟settings类,但跟踪器的构造函数无法实际使用设置类,因为它在编译时固定为直接引用settings

该菜谱确实在“ Mocking Nonvirtual Methods”下说明了如何解决此问题:首先,创建您的模拟类,然后提供一些依赖注入方法,供您选择在编译时在类的生产版本和模拟版本之间切换。一种方法是使tracker成为一个由settings类参数化的类模板,例如:

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>

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