Предисловие: Я знаю, что следующее - очень грязный хак.Мы будем рефакторировать вещи (чтобы мы могли писать нехакерские тесты, использовать Mocks и, возможно, даже избавляться от синглетонов), но сначала нам нужно тестовое покрытие ...
Как уже было сказано, у нас есть значительное числоклассов типа «Синглтон» в нашем проекте, то есть что-то вроде.
class SomeSingleton
{
public:
static SomeSingleton& getSingleton()
{
if (m_singletonInstance == nullptr)
m_singletonInstance = new SomeSingleton();
return *m_singletonInstance;
}
protected:
SomeSingleton();
virtual ~SomeSingleton();
static SomeSingleton* m_singletonInstance = nullptr;
}
Чтобы правильно запустить наши модульные тесты, синглтон должен быть «сброшен» (или данные наших предыдущих тестов могутсохраняться в синглтоне, влияя на текущий тест).К сожалению, нет подходящего способа сделать это (экземпляр Singleton и деструктор защищены).
Мы не хотим изменять наш производственный код так, чтобы он содержал функциональность только для тестирования (то есть без прямого объявления ::test::SomeSingletonResetter
как друг в SomeSingleton, не вводите общедоступную функцию void resetSingleton_forTestUseOnly()
и т. д.), и мы также хотим избежать каких-либо существенных изменений в производственном коде, пока у нас не будет тестового покрытия.
Итак, вот грязнаяХак, который мы рассматриваем: В тестовом проекте мы извлекаем очень простой класс-обертку (то есть без членов) из Singleton со статической функцией, которая delete
s синглтоном - однако, поскольку деструктор не может быть вызван даже из производного класса (онзащищен) мы бы static_cast синглтона для производного класса и удалили это:
class SomeSingletonWrapper : public SomeSingleton
{
public:
SomeSingletonWrapper();
~SomeSingletonWrapper() override;
static void reset()
{
//can't delete/call destructor on SomeSingleton since it is protected
delete static_cast<SomeSingletonWrapper*>(m_singletonInstance);
m_singletonInstance = nullptr;
}
}
Мы думаем, что классы по существу одинакового размера, и деструктор производных классов вызовет базовый деструктор, поэтомукласс уничтожается должным образом.Может ли это сработать (пока мы не сможем что-то изменить) или это ужасно взорвется на наших лицах?И есть ли лучший (менее хакерский) способ архивировать это (без значительного изменения производственного кода)?
Редактировать:
Я знаю, что альтернатива будет иметьЯ просто не вызывал деструктор (и только устанавливал m_singletonInstance = nullptr
), но это было бы еще хуже, так как теперь я теряю память при каждом тесте, и эти синглтоны продолжают плавать, пока тестовое приложение не завершится, выполняя "бог знает что" ..Бррр ....