【问题标题】:event expected not to raise is raising预计不会引发的事件正在引发
【发布时间】:2012-10-01 07:57:18
【问题描述】:

我有一个活动和一个筹款方法如下:

public class Events {

    public event EventHandler<CustomEventArgs> Succeed;

    public virtual void OnSucceed(object sender, params object[] data)
    {
        CustomEventArgs args = new CustomEventArgs(data);

        EventHandler<CustomEventArgs> _succeed = Succeed;

        if (_succeed != null)
        {
            _succeed(sender, args);
        }

    }}

我为 OnSucceed 方法创建了一个单元测试(使用FluentAssertions):

    [Test]
    public void SucceedShouldNotBeRaisedTest()
    {
        Events events = new Events();

        events.MonitorEvents();

        events.OnSucceed(this,"somedata");

        events.ShouldNotRaise("Succeed");
    }

由于该事件没有订阅者,所以我希望它不会引发成功事件

但测试失败,因为成功事件 引发。这是怎么回事?!

【问题讨论】:

    标签: asp.net unit-testing events event-handling nunit


    【解决方案1】:

    当您调用events.MonitorEvents(); 时,FluentAssertions 会自动订阅公共事件以检测何时引发事件。

    您的测试失败,因为您的条件将始终评估为true:if (_succeed != null)。测试时,事件总是与null不同

    现在我想向您推荐 Jon Skeet 提出的以下方法:

    public event EventHandler<CustomEventArgs> Succeed = delegate { } ;
    

    使用上述事件声明,您的事件将永远不会是null(不能从其类之外分配事件)

    注意:您可以将事件背后的委托在其类中分配为 null,如下所示:

    this.Succeed = null;
    

    上述语句是将事件背后的委托分配为 null,而不是事件本身。通常你不需要做这样的事情,但如果你这样做,你必须像这样重新初始化事件:

    this.Succeed = null;
    this.Succeed = delegate { };
    

    如果您遵循这些建议,您的事件将永远不会为空,并且您无需再调用 if(this.MyEvent != null) 条件来引发您的事件。 (请注意,这种情况完全是技术性的,与域本身无关。)

    现在您已经移除了该技术条件,您可以真正关注域规则来决定何时引发事件。

    最后一步是删除:if (_succeed != null) 并添加一个条件,指示是否应该根据您当前的域引发事件

    if(shouldRaiseEvent)
    {
        EventHandler<CustomEventArgs> _succeed = Succeed;
    
        _succeed(...);
    }
    

    对于您的测试,您只需要使用所需的条件配置您的测试对象,以便引发或不引发您的事件。

    完整样本:

    public class Events {
    
    public event EventHandler<CustomEventArgs> Succeed = delegate { };
    
    public virtual void OnSucceed(object sender, params object[] data)
    {
        if (/*[optional] here your domain condition that will indicate if the event should be raised*/)
        {
            // this is a best practice to deal with multi-threading situations
            var _succeed = this.Succeed;
            var args = new CustomEventArgs(data);
    
            _succeed(sender, args);
        }
    
    }
    }
    

    【讨论】:

    • 谢谢您,先生,那么哪个分配空语句是首选?实际上,我对第一个感觉更好( event = delegate {} )
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多