понедельник, 16 мая 2011 г.

Тестирование конфигурации AutoMapper

На верное многие уже слышали про  AutoMapper и знают что это такое, но если нет, то  вкратце расскажу. AutoMapper - это object - object  mapper.  AutoMapper полезен, когда надо, например, из объектов модели данных скопировать лишь некоторые свойства в объекты  DTO.

Например у нас есть класс Order и класс OrderItem  для примера данные классы сильно упрощены.

    public class Order
    {
        public string Number { get; set; }
        public List<OrderItem> OrderItems { get; set; }
        public DateTime Date { get; set; }
    }

    public class OrderItem
    {
        public int Quantity { get; set; }
        public decimal Price { get; set; }
    }

Пусть необходимо на клиенте отобразить следующие данные о заказе номер, дату, общую сумму заказа, количество единиц в заказе, для  этого создаем класс DTO
    public class OrderDto
    {
        public string Number { get; set; }
        public DateTime Date { get; set; }
        public decimal TotalAmount { get; set; }
        public int TotalItems { get; set; }
    }

Предположим, что данные о заказах уже получены, каким либо способом.  Теперь задача состоит в том, чтобы преобразовать коллекцию объектов Order состоит в коллекцию объектов OrderDto. Тут и приходит на помощь AutoMapper. Для начала надо настроить конфигурацию в простом случае для этого достаточно написать
Mapper.CreateMap<Order, OrderDto>();

многое делать такие свойства как Date и Number будут преобразованы автоматически, так как имена в обоих классах совпадают. Для настройки преобразования в более сложных случаях как с полями TotalItems в AutoMapper есть очень удобное fluent API. Вот как это выглядит
    public class AutomapperConfigurator
    {
        public static void RegisterMappings()
        {
            Mapper.CreateMap<Order, OrderDto>()
                .ForMember(x => x.TotalItems, o => o.MapFrom(y => y.OrderItems.Count));
       }
    }

Так как для преобразования используются конвенции наименования, то хотелось бы протестировать, правильно ли все настроено, для этого предусмотрен специальный метод  AssertConfigurationIsValid(), данный метод проверяет, что для каждого поля целевого класса (OrderDto) имеется соответствующее поле из класса источника  либо правильная настройка. Юнит тест может быть следующим:
       [Test]
        public void TheAutoMapperConfigurationShouldBeValid()
        {
            //Arange
             AutoMapper.Mapper.Reset();
            //Act
            AutomapperConfigurator.RegisterMappings();
            //Assert
            AutoMapper.Mapper.AssertConfigurationIsValid();                            
        }

При запуске данного теста, если что-то не в порядке получаем исключение с описанием свойства, которое не настроено в данном случае получаем:
AutoMapper.AutoMapperConfigurationException: The following 1 properties on AutoMapper.Tests.OrderDto are not mapped: TotalAmount
Все правильно, ведь мы не настроили конфигурацию для TotalAmount исправить это можно используя метод Ignore(), который просто проигнорирует это поле
                .ForMember(x => x.TotalAmount, o => o.Ignore());

но так как это поле нам нужно, то напишем правильную конфигурацию
Mapper.CreateMap<Order, OrderDto>()
     .ForMember(x => x.TotalItems, o => o.MapFrom(y => y.OrderItems.Count))
     .ForMember(x => x.TotalAmount, o => o.MapFrom(y => y.OrderItems.Sum(c => c.Price*c.Quantity)));


Теперь, когда все про тестировано, для преобразования объектов достаточно написать

var orderDtos = Mapper.Map<List<Order>, List<OrderDto>>(orders);

и мы получим заполненную коллекцию объектов OrderDto.
Вот и все надеюсь этот пост будет полезным.

Комментариев нет:

Отправить комментарий