#c #linker #mocking #overriding
#c #компоновщик #издевательство #переопределение
Вопрос:
Мне нужно смоделировать некоторые классы с помощью GoogleMock и изменить реализацию базового класса так, чтобы он фактически создавал экземпляр этого издевательского. Базовый класс генерируется автоматически вместе с некоторыми другими классами, которые не нужно издеваться, и все они добавляются в одну библиотеку.
Классы, которые необходимо издеваться, создаются с помощью фабрики, через которую я намерен вернуть дочерний класс. Могу ли я «повторно связать» с этой новой библиотекой, которая имеет реализацию для уже связанного базового класса?
Чего я надеюсь достичь, так это получить экземпляр базового класса из тестируемого модуля, а затем преобразовать его в издевательский.
Пример кода:
Original.hpp
class Base
{
private:
Base();
public:
virtual ~Base();
static std::shared_ptr<Base> createInstance();
}
Original.cpp
#include "Original.hpp"
...
std::shared_ptr<Base> Base::createInstance()
{
return std::shared_ptr<Base>(new Base());
}
...
Modified.hpp
class Derived : public Base
.....
Modified.cpp
#include "Original.hpp"
#include "Modified.hpp"
...
std::shared_ptr<Base> Base::createInstance()
{
return std::shared_ptr<Base>((Base*) new Derived());
}
Поэтому я хочу, чтобы всякий раз, когда базовый класс создается через CreateInstance в любом месте проекта, CreateInstance, определенный в Modified.cpp вместо этого будет использоваться для возврата производного класса.
Комментарии:
1. Вопрос мне неясен. Покажите код вашей системы, фабрики и интерфейса для класса, который вы хотите издеваться.
2. @Ptaq666 я добавил несколько примеров кода. К вашему сведению, это для издевательства над бережливыми клиентами, но я не смог добавить исходный код, но пример должен быть понятнее
Ответ №1:
Хорошо, я думаю, я более или менее понимаю. Если библиотека уже скомпилирована, вы не можете изменить реализацию этого статического фабричного метода. Если вы предоставите свою собственную реализацию и попытаетесь связать ее с существующей библиотекой, у вас будет несколько определений (не допускается). Что вы можете сделать, так это добавить в ваше приложение один слой, который будет отвечать за Base
создание этих объектов:
// existing implementation
class Base {
public:
virtual ~Base();
static std::shared_ptr<Base> createInstance() {
return std::shared_ptr<Base>(new Base());
}
private:
Base() {};
};
// new layer, part of your production code
class IYourFactory {
public:
virtual ~IYourFactory() = default;
virtual std::shared_ptr<Base> createInstance() = 0;
};
// new layer, part of your production code
class ProductionFactory: public IYourFactory {
public:
~ProductionFactory() override = default;
std::shared_ptr<Base> createInstance() override {
return Base::createInstance();
}
};
// testing code, you can use GMock to create this class
class MockBase: public Base {
public:
// it's a hack for Base private default constructor
MockBase(): Base(*Base::createInstance()) {}
~MockBase() override = default;
};
// testing code, you can use GMock to create this class
class MockFactory: public IYourFactory {
~MockFactory() override = default;
std::shared_ptr<Base> createInstance() override {
return std::make_shared<MockBase>();
}
};
class YourSystem {
public:
YourSystem(std::shared_ptr<IYourFactory> factory): factory_(factory) {}
bool doSomeThings() {
auto basePtr = factory_->createInstance();
return true;
}
private:
std::shared_ptr<IYourFactory> factory_;
};
Конечно, это будет работать только в том случае, если Base
у класса есть некоторые виртуальные функции, которые вы можете override
использовать в своем MockBase
. Если нет, то это не тот путь (вам нужно будет создать свой собственный интерфейс для методов, предлагаемых Base
).
Точное решение зависит от того, как вы используете его в своей системе и к какому интерфейсу Base
.