Допустим, у нас есть следующие классы A
а также B
:
class A
{
virtual void Init() { DoSomething(); }
};
class B : public A
{
virtual void Init() { DoSomethingSpecial(); A::Init(); }
};
В нашем модульном тесте мы хотим только проверить B
то есть проверить с помощью Hippomocks это призвание B::Init()
на самом деле позвонит DoSomethingSpecial()
:
B* b_p = new B();
m_mockRepository_p->ExpectCall(b_p, DoSomethingSpecial);
b_p->Init();
Теперь мы не хотим ожидать всех звонков от A
«s Init()
поэтому мы хотели бы написать что-то вроде:
m_mockRepository_p->ExpectCall(b_p, A::Init);
Последнее ожидание вызывает необработанное исключение, которое, я думаю, нормально, поскольку мы смешиваем метод, который мы вызываем, с его базовой версией, которую мы хотим ожидать. Кастинг b_p
для A
не помогает
Есть ли решение для этого конкретного варианта использования?
… Это интересный. Я думаю, что нет никакого решения для этого. Вызов A :: Init не выполняется через таблицу виртуальных функций (как вы точно знаете, какую из них вызывать), поэтому он относится к не виртуальным функциям, которые вы не можете имитировать.
Осложняющим фактором для добавления этого является то, что если вы взяли адрес A :: Init на B, вы все равно получили бы указатель vtable, так что вы даже не могли бы заменить функцию, если хотите (скажем, с помощью насмешки над функцией C). логика).
Я могу только порекомендовать общие решения по рефакторингу, чтобы решить эту проблему — сделать A и B независимыми классами, заставить B содержать A (частное наследование) или извлечь интерфейс из A и B и превратить B в декоратор. Последнее звучит лучше, но это зависит от того, что A и B на самом деле …
Других решений пока нет …