#c #mocking #googletest
#c #насмешливый #googletest
Вопрос:
Рассмотрим следующий фрагмент кода:
источник.hpp
class tracker
{
public:
static trackeramp; get_instance()
{
static tracker instance;
return instance;
}
tracker(const trackeramp;) = delete;
trackeramp; operator=(const trackeramp;) = 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
trackeramp; inst = tracker::get_instance();
}
int main(int argc, char** argv)
{
::testing::InitGoogleMock(amp;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:
Похоже, что проблема, с которой вы можете столкнуться здесь, заключается в том, что вы пытаетесь имитировать класс settings
, но у конструктора tracker нет возможности фактически использовать ваш класс mock settings, потому что во время компиляции исправлено прямое обращение к settings
.
В кулинарной книге действительно объясняется, как это решить, в разделе «Имитирующие невиртуальные методы«: сначала вы создаете свой макет класса, затем предоставляете некоторые средства внедрения зависимостей, которые позволяют вам выбирать между производственной и макетной версиями класса во время компиляции. Одним из способов сделать это было бы сделать tracker шаблоном класса, параметризованным с помощью класса settings чем-то вроде:
template <typename settings_class> class tracker_template
{
public:
static tracker_template<settings_class>amp; 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 в вашем производственном коде и вместо этого использовать tracker_template<MockSettings>
в вашем тестовом коде.
Вероятно, нет способа решить это без изменения вашего кода.