Переопределение ссылок в Cpp для указания на ложную реализацию - PullRequest
0 голосов
/ 12 апреля 2019

Мне нужно смоделировать некоторые классы с помощью 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 Ответ

1 голос
/ 12 апреля 2019

ОК, я думаю, что понимаю более или менее. Если библиотека уже скомпилирована, вы не можете изменить реализацию этого статического метода фабрики. Если вы предоставляете свою собственную реализацию и пытаетесь связать ее с существующей библиотекой, у вас будет несколько определений (не разрешено). Что вы можете сделать, это добавить один слой к вашему приложению, который будет отвечать за создание 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.

...