Я использую статический полиморфизм CRTP на сервере веб-сокетов, чтобы отделить сетевой код от бизнес-логики. Базовый класс вызывает методы производного класса для обработки сообщений, производный, в свою очередь, вызывает базовый класс для отправки/получения. Это работает как шарм, выглядит примерно так:
template<typename Derived>
class WebsocketSessionBase {
// basic websocket send/receive stuff
void someBaseMethod() {
static_cast<Derived*>(this)->otherDerivedMethod();
}
};
class WebsocketSession : public WebsocketSessionBase<WebsocketSession> {
// specific business logic
void someDerivedMethod() {
otherBaseMethod();
}
};
Теперь идет модульное тестирование. Поскольку код развязан, я бы хотел, чтобы тестовая функциональность в классах была отдельно.
Тестировать базовый класс просто:
class TestSession : public WebsocketSessionBase<TestSession> {
// same interface as WebsocketSession, but test code, cool!
};
Но как протестировать производный класс? Мне пришло в голову добавить параметр шаблона Base, что делает тестовый код в порядке (Base — это фиктивный класс). Но в итоге у меня есть 2 класса шаблонов, ссылающихся друг на друга в производственной версии... :(
template<typename Base>
class TestableWebsocketSession : public Base {
};
using TestedWebsocketSession = TestableWebsocketSession<MockBase>;
using ProdWebSocketSession = TestableWebsocketSession<WebsocketSessionBase<... // infinite loop - now what!?
Можно ли пройти через это?