Сервисный уровень моего приложения ASP.NET MVC 3 использует AutoMapper для сопоставления моделей представлений с бизнес-объектами.Я реализовал преобразователи типов для преобразования идентификаторов объектов, представленных в запросе post / get, в бизнес-объекты. Преобразователи типов выполняют поиск сущностей в базе данных по идентификаторам и перестраивают бизнес из них.Например:
class UserViewModel {
// user fields
Guid? Manager; // this is an ID of another user in the system
}
Служба вызовет AutoMapper:
var userModel = Mapper.Map<UserViewModel, UserModel>(viewModel);
для сопоставления с этим классом:
class UserModel {
// other fields...
UserModel Manager;
}
с помощью преобразователя типов, который выгляделдругого пользователя в базе данных по GUID менеджера из модели представления.Преобразователи типов внедряются в зависимости с помощью Ninject, и все отлично работает в веб-приложении.
Я пытаюсь написать модульный тест, который будет использовать фиктивные репозитории с преобразователями типов.AutoMapper может быть настроен для создания служб с использованием предоставленной пользователем функции:
Mapper.Initialize(cfg =>
{
cfg.ConstructServicesUsing(type => Kernel.GetService(type));
});
В веб-приложении Kernel is Ninject, для тестов я решил предоставить свой собственный метод, который возвращает экземпляры запрошенных типов из словаря:
Dictionary<Type, object> typeDict = new Dictionary<Type, object>()
{
{ typeof(IRepository), new MockRepository() }
};
...
Mapper.Initialize(cfg =>
{
cfg.ConstructServicesUsing(type => { return typeDict[type]; } );
});
Идея заключалась в том, что когда AutoMapper настроен на преобразование Guid в объект, подобный этому:
Mapper.CreateMap<Guid?, TDropDown>()
.ConvertUsing<GuidToSelectListValueConverter<TDropDown>>();
, и ему необходимо создать новый экземпляр GuidToSelectListValueConverter и внедрить его с помощью репозитория.запросит тип IRepository с помощью метода, настроенного в ConstructServicesUsing.
Вместо этого AutoMapper фактически пытается получить экземпляр типа GuidToSelectListValueConverter.Это означает, что я отвечаю за создание нового экземпляра конвертера типов и добавление его в зависимости.Вместо этого мой typeDict должен выглядеть следующим образом:
Dictionary<Type, object> typeDict = new Dictionary<Type, object>()
{
{ typeof(GuidToSelectListValueConverter), new GuidToSelectListValueConverter(
new MockRepository()) }
};
У меня есть много преобразователей типов, и ручная запись функций распознавателя для них не представляется осуществимой.Так что это заставило меня задуматься.Было бы неправильно просто настроить Ninject для разрешения этих зависимостей в моем модульном тесте?Я мог бы связать IRepository с MockRepository, а затем, когда мне понадобится экземпляр службы, просто вызвать Kernel.GetService (typeof (MyService)) и заставить Ninject внедрить его с помощью MockRepository.Дополнительным преимуществом является то, что AutoMapper будет также использовать Ninject для получения экземпляров преобразователей типов и преобразователей значений:
// configure Ninject
Kernel.Bind<IRepository>().To<MockRepository>();
// initialize AutoMapper
Mapper.Initialize(cfg =>
{
cfg.ConstructServicesUsing(t => Kernel.GetService(t));
});
// create an instance of service to test
var service = Kernel.GetService(IMyService);
// do work
var result = service.DoWork();
// analyze result
Теперь, когда метод DoWork вызывает метод Mapper. Преобразователи типов создаются с использованием Ninject.
Любые предложения, идеи и советы передового опыта приветствуются.
Спасибо!