Как выполнить модульное тестирование подписки на события с помощью NUnit - PullRequest
1 голос
/ 27 февраля 2012

Привет, интересно, кто-нибудь знает ответ на мой вопрос:

Рассмотрим следующий код

class TheHandler
{
    ...
    Public EventHandler myRealWorldEvent;
    ...


}

class TheSubscriber
{
    private TheHandler myHandler = new TheHandler();

    public subscribeToHandler()
    { 
        myHandler.myRealWorldEventHandler += OnSomethingHappens;

    }

     ...

    pirvate OnSomeThingHappens()
    {
       ...
    }
}

Мой вопрос здесь -> как я могу проверить (только с NUnit), что OnSomethingHappens подписаны на myRealWorldEventHandler. Я не могу изменить код SUT / production и не могу использовать Mock (Moq / Nmock и т. Д.). Кто-нибудь знает решение моей проблемы?

С уважением,

zhengtonic

Ответы [ 2 ]

1 голос
/ 27 февраля 2012

NUnit этого не делает - проверяет, подписан ли какой-то приватный обработчик на какое-то приватное поле.Здесь задействовано слишком много личных вещей.Тем не менее, это ничто, что вы не можете сделать с небольшой помощью отражения.Обратите внимание, что это не очень красивый код:

var subscriber = new TheSubscriber();
var handlerField = typeof(TheSubscriber)
    .GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
    // if field with such name is not present, let it fail test
    .First(f => f.Name == "myHandler");

var handlerInstance = handlerField.GetValue(subscriber);
var someEventField = typeof(TheHandler)
    .GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
    .First(f => f.Name == "myRealWorldEvent");

var eventInstance = (EventHandler) someEventField.GetValue(handlerInstance);
var subscribedMethod = eventInstance
    .GetInvocationList()
    .FirstOrDefault(d => d.Method.Name == "OnSomethingHappens");

Assert.That(subscribedMethod, Is.Not.Null);

Если вам приходится сталкиваться с множеством тестирований унаследованных систем (т. Е. Частных членов, статических членов - то, что бесплатные фреймворки плохо или вовсе не обрабатывают)) - предлагаю взглянуть на такие инструменты, как TypeMock или JustMock .

0 голосов
/ 13 октября 2015

Была такая же проблема.Код от jimmy_keen не работал должным образом со старыми .NET.Решил это, написав вспомогательные методы:

public static void assertSubscribed<EventHandlerType>(object handler, object subscriber, string eventName = null) {
    var inappropriate = false;
    try {
        if (!typeof (EventHandlerType).IsSubclassOf(typeof (Delegate)) ||
            typeof (EventHandlerType).GetMethod("Invoke").ReturnType != typeof (void))
            inappropriate = true;
    } catch (AmbiguousMatchException) {
        inappropriate = true;
    } finally {
        if (inappropriate) throw new Exception("Inappropriate Delegate: " + typeof (EventHandlerType).Name);
    }

    var handlerField = subscriber.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
        .First(h => h.FieldType.IsInstanceOfType(handler));

    var handlerInstance = handlerField == null ? null : handlerField.GetValue(subscriber);
    var eventField = handlerInstance == null ? null : handlerInstance.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
        .First(f => (f.FieldType.IsAssignableFrom(typeof (EventHandlerType)) &&
                     (eventName == null || eventName.Equals(f.Name))));

    var eventInstance = eventField == null ? null : (Delegate)eventField.GetValue(handlerInstance);
    var subscribedMethod = eventInstance == null
        ? null 
        :eventInstance.GetInvocationList().FirstOrDefault(
            d => d.Method.DeclaringType != null && d.Method.DeclaringType.IsInstanceOfType(subscriber));

    Assert.That(subscribedMethod, Is.Not.Null);
}

"Not" метод:

public static void assertNotSubscribed<EventHandlerType>(object handler, object subscriber, string eventName = null) {
    var inappropriate = false;
    try {
        if (!typeof (EventHandlerType).IsSubclassOf(typeof (Delegate)) ||
            typeof (EventHandlerType).GetMethod("Invoke").ReturnType != typeof (void))
            inappropriate = true;
    } catch (AmbiguousMatchException) {
        inappropriate = true;
    }
    if (inappropriate) return;

    var handlerField = subscriber.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
        .First(h => h.FieldType.IsInstanceOfType(handler));

    var handlerInstance = handlerField == null ? null : handlerField.GetValue(subscriber);

    var eventField = handlerInstance == null ? null : handlerInstance.GetType()
        .GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
        .First(f => (f.FieldType.IsAssignableFrom(typeof (EventHandlerType)) &&
                     (eventName == null || eventName.Equals(f.Name))));

    var eventInstance = eventField==null?null:(Delegate) eventField.GetValue(handlerInstance);
    var subscribedMethod = eventInstance == null
        ? null
        : eventInstance.GetInvocationList().FirstOrDefault(
                d => d.Method.DeclaringType != null && d.Method.DeclaringType.IsInstanceOfType(subscriber));

    Assert.That(subscribedMethod, Is.Null);
}

И вызов:

assertSubscribed<EventHandler>(handler, subscriber);
assertNotSubscribed<EventHandler>(handler, subscriber);
assertSubscribed<EventHandler>(handler, subscriber, "myRealWorldEvent");
assertNotSubscribed<EventHandler>(handler, subscriber, "myRealWorldEvent");

Не мешайте мне по стилю кодасоглашение, но этот метод выглядит достаточно компактным.

...