Библиотека для создания класса, который имеет встроенный конструктор в другой сборке со случайными данными?

Я получаю уведомления о событиях от веб-служб, которые запускают обработчики событий с данными о том, что вызвало событие. Я пытаюсь проверить, как только обработчик события называется a, b а также c все вызываются с правильными значениями. Это невозможно без использования веб-службы.

Мое решение заключается в создании конвертеров, которые преобразуют EventArgs которые возвращаются мне через библиотеку служб (веб-службы Exchange), что-то, что мои тупые объекты могут понять, не полагаясь на службы третьей части. Моя проблема в том, что EventArgs Класс, данный my библиотекой EWS, имеет внутренний конструктор, поэтому нет простого способа создать его экземпляр со случайными значениями свойств без особой работы с отражением.

Например, у меня есть простой интерфейс:

public interface IConverter<TFrom, TTo>
{
    TTo Convert(TFrom from);
}

и простая реализация:

public class NotificationEventArgsConverter : IConverter<NotificationEventArgs, NewNotification>
{
    public NewNotification Convert(NotificationEventArgs from)
    {
        return new NewNotification
                   {
                       ItemIds = from.Events.Cast<ItemEvent>().Select(x => x.ItemId.ToString())
                   };
    }
}

Вопрос в том, как я могу создать экземпляр NotificationEventArgs со случайными значениями. Есть ли библиотека для этого, которую я пропустил в своих поисках?

Вся цель этого состоит в том, чтобы подражать, если я получаю экземпляр NotificationEventArgs со следующими значениями тогда NewNotification должен напоминать x,

редактировать

А пока я просто буду использовать typeof(T).GetConstructor(),

2 ответа

Решение

Возможно, вы захотите взглянуть на AutoFixture:

AutoFixture облегчает разработчикам разработку через тестирование, автоматизируя несоответствующую настройку Test Fixture, позволяя разработчику тестов сосредоточиться на основных моментах каждого теста.

Выполнив некоторую декомпиляцию Microsoft.Exchange.WebServices и поиграв с отражением, вы можете сделать это, например, так:

var fixture = new Fixture();

// retrieve internal FolderEvent(EventType, DateTime) ctor
// using FolderEvent class as NotificationEvent is abstract
var notificationEventCtor = typeof(FolderEvent).GetConstructor(
    BindingFlags.NonPublic | BindingFlags.Instance,
    null,
    new Type[] { typeof(EventType), typeof(DateTime) },
    null
);

// generate 10 random events with some help of LINQ and AutoFixture
var trashData = Enumerable
    .Range(1, 10)
    .Select(i => new object[]
        {
            fixture.CreateAnonymous<EventType>(),
            fixture.CreateAnonymous<DateTime>() 
        })
    .Select(p => notificationEventCtor.Invoke(p))
    .Cast<NotificationEvent>()
    .ToList();

Код выше сгенерирует 10 FolderEvents в списке, готовы перейти к NotificationEventArgs конструктор (который снова является внутренним, поэтому применяется тот же код):

var notificationEventArgsCtor = typeof(NotificationEventArgs).GetConstructor(
    BindingFlags.NonPublic | BindingFlags.Instance,
    null,
    new Type[] 
    { 
        typeof(StreamingSubscription),
        typeof(IEnumerable<NotificationEvent>) 
    },
    null
);

var instance = notificationEventArgsCtor
    .Invoke(new object[] { null, trashData });

Взгляните на класс PrivateObject (в частности, эти перегрузки конструктора). Он оборачивает всю работу по отражению для вас и позволяет создавать объекты с непубличными конструкторами, а также получать доступ к закрытым методам и свойствам этих объектов. Вы можете получить базовые объекты через свойство Target.

Другие вопросы по тегам