GTest: насмешливая не виртуальная функция-член - PullRequest
1 голос
/ 07 марта 2019

Рассмотрим следующий фрагмент кода:

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 Ответ

1 голос
/ 07 марта 2019

Похоже, что проблема, с которой вы здесь можете столкнуться, заключается в том, что вы пытаетесь смоделировать класс settings, но у конструктора трекера нет способа на самом деле использовать ваш класс настроек ложных настроек,потому что во время компиляции исправлено прямое обращение к settings.

В «Кулинарной книге» действительно объясняется, как решить эту проблему, в разделе « Пересмешливые невиртуальные методы »: во-первых, вы делаете свой макет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> в вашем тестовом коде.

Вероятно, не существует способа решить эту проблему без изменения вашего кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...