Один из способов - не связывать ваши классы таким образом.
Используя ваш пример:
myDataClass будет чисто виртуальным классом. Это будет иметь как минимум 2 реализации: «реальную» и макетную.
Ваш тестовый код может внедрить ложный экземпляр, имея 2 конструктора, один из которых принимает myDataClass, а другой - нет. Посмотрите код ниже для примера.
class myWorkerClass {
public:
myWorkerClass(myDataClass * dc) : m_dc(dc) {}
myWorkerClass() : m_dc(new MyRealDataClass()) { }
~myWorkerClass { delete m_dc; }
private:
myDataClass *m_dc;
}
Теперь вы можете предоставить любую реализацию myDataClass для myWorkerClass, которую вы хотите. Если вы не предоставляете реализацию, тогда ваш код возвращается к «реальной» реализации.
Другой метод - использовать шаблон Factory для создания экземпляров ваших объектов. Ваш тестовый код может установить некоторый флаг на фабрике, который создает экземпляры myDataClass и заставляет его создавать фиктивный объект вместо реального. Я предпочитаю первый метод, так как для меня его немного проще использовать (плюс мне не нужно поддерживать заводской класс для всего, что я хочу протестировать)