如何使用NUnit对事件子分区进行单元测试

本文关键字:分区 单元测试 事件 何使用 NUnit | 更新日期: 2023-09-27 18:25:50

嗨,我想知道是否有人知道我的问题的答案:

考虑以下代码

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

}
class TheSubscriber
{
    private TheHandler myHandler = new TheHandler();
    public subscribeToHandler()
    { 
        myHandler.myRealWorldEventHandler += OnSomethingHappens;
    }
     ...
    pirvate OnSomeThingHappens()
    {
       ...
    }
}

我的问题是->我如何测试(仅使用NUnit)OnSomethingHappens订阅了myRealWorldEventHandler。我不能更改SUT/生产代码,也不能Mock(Moq/Nmock等)。有人知道我的问题的解决方案吗?

致问候,

正通

如何使用NUnit对事件子分区进行单元测试

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或JustLock等工具。

也有同样的问题。来自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);
}

"非"方法:

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");

不要为代码样式约定而打扰我,但这个方法看起来足够紧凑。