1

我有一个事件和一个提升方法如下:

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

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

但测试失败,因为引发了成功事件。这有什么问题?!

4

1 回答 1

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

}
}
于 2012-10-01T08:28:53.327 回答