Мы работаем с очень старой унаследованной системой, реализованной на C ++ с компилятором VC6.Сейчас мы находимся в процессе рефакторинга кода.Мы также переключились на компилятор VC9.
Мы используем внешнюю проприетарную платформу, которая также является устаревшим кодом и не может тестироваться модулем.Для того, чтобы сделать наш блок кода тестируемым, мы ввели интерфейсы и оболочки для классов инфраструктуры (подсказка: см. «Работа с устаревшим кодом» от Мартина Фаулера):
Теперь мы зависим от интерфейсов.Оболочки вызывают методы фреймворка, и мы можем с радостью использовать mocks в наших модульных тестах.
И здесь мы подходим к нашей проблеме ...
Классы фреймворка содержат много методов, которые необходимо обернутьи издевались.Чтобы достичь этой цели, наша команда поставщиков написала API, который генерирует интерфейсы, оболочки и реализации макетов с использованием макросов C ++.
Пример файла заголовка оболочки:
class PlanWrapper : public IPlan
{
// ...
WRP_DECLARE_DEFAULTS(FrameworkPlan); // macro
WRP_DECLARE_CSTR_ATTR(FrameworkPlanLabel); // macro
// ...
};
МакросWRP_DECLARE_CSTR_ATTR определяется следующим образом:
#define WRP_DECLARE_CSTR_ATTR(AttrName) \
virtual bool set##AttrName (LPCTSTR Value_in); \
virtual bool get##AttrName (CString& Value_out); \
virtual bool unset##AttrName (); \
virtual bool isSet##AttrName ()
Пример файла cpp оболочки:
#include "StdAfx.h"
using namespace SomeNamespace;
WRP_IMPLEMENT_MODDICOM_DEFAULTS(FrameworkPlan)
WRP_IMPLEMENT_W_CSTR_ATTR (FrameworkPlan,FrameworkType1, FrameworkPlanLabel)
// ...
Макрос WRP_IMPLEMENT_W_CSTR_ATTR определяется следующим образом:
#define WRP_IMPLEMENT_W_CSTR_ATTR(ClassName,AtrTypeObj,AttrName) \
bool ClassName##Wrapper::set##AttrName (LPCTSTR Value_in) { \
AtrTypeObj aValue = Value_in; \
FrameworkLink<ClassName> convertedObj = NULL_LINK; \
framework_cast(convertedObj, m_Object); \
return convertedObj != NULL_LINK ? \
convertedObj->set##AttrName (aValue) : false; \
}
// ...
У нас естькуча еще более сложных вещей, но я думаю, вы поняли.
Проблема с API заключается в том, что он чрезвычайно сложен, не читается, не отлаживается и не тестируется.
Мы хотели бы придумать лучший механизм для достижения той же цели.Идея заключалась в том, что мы используем некоторые из расширенных функций, которые пришли с новым компилятором, такие как расширенные шаблоны, списки типов, черты и т. Д.
С помощью шаблонов мы можем почти достичь нашей цели, но мы застряли с именами методов.Мы можем обобщать для типов, но как нам обращаться с именами атрибутов?
Мы также подумали о создании инструмента для автоматической генерации кода обертки + интерфейсы + mocks.Однако API нашей внешней структуры чрезвычайно сложен, и написание такого инструмента будет очень дорогостоящим.
Что, по вашему мнению, является лучшим способом решения такой проблемы?Может быть, вы уже имели дело с чем-то подобным и можете дать хорошие подсказки?Мы с нетерпением ждем ваших ответов!