NSubstitute完全手册(十四)引发事件

有时,引发被替代的类型中定义的事件时非常必要的。例如下面这个例子:

 1     public interface IEngine
 2     {
 3       event EventHandler Idling;
 4       event EventHandler<LowFuelWarningEventArgs> LowFuelWarning;
 5       event Action<int> RevvedAt;
 6     }
 7 
 8     public class LowFuelWarningEventArgs : EventArgs
 9     {
10       public int PercentLeft { get; private set; }
11       public LowFuelWarningEventArgs(int percentLeft)
12       {
13         PercentLeft = percentLeft;
14       }
15     }

在 .NET 中,事件是非常有意思的功能,因为你不能像操作其他成员似地进行传递。相反地,你只能添加或移除事件处理器,NSubstitute 正是使用了这个添加事件处理器的语法来引发事件。

 1     [TestMethod]
 2     public void Test_RaisingEvents_RaiseEvent()
 3     {
 4       var engine = Substitute.For<IEngine>();
 5 
 6       var wasCalled = false;
 7       engine.Idling += (sender, args) => wasCalled = true;
 8 
 9       // 告诉替代实例引发异常,并携带指定的sender和事件参数
10       engine.Idling += Raise.EventWith(new object(), new EventArgs());
11 
12       Assert.IsTrue(wasCalled);
13     }

在上面的例子中,我们不能真实地了解到我们所引发事件的发送者和参数,仅是知道它被调用了。在这种条件下,NSubstitute 通过为我们的事件处理器创建所需的参数,来使该操作更便捷些。

 1     [TestMethod]
 2     public void Test_RaisingEvents_RaiseEventButNoMindSenderAndArgs()
 3     {
 4       var engine = Substitute.For<IEngine>();
 5 
 6       var wasCalled = false;
 7       engine.Idling += (sender, args) => wasCalled = true;
 8 
 9       engine.Idling += Raise.Event();
10       Assert.IsTrue(wasCalled);
11     }

当参数没有默认构造函数时引发事件

NSubstitute 不总是能够创建事件参数。如果事件的参数没有默认的构造函数,你可能不得不使用 Raise.EventWith<TEventArgs>(...) 来创建事件参数,例如下面例子中的 LowFuelWarning 事件。如果没有提供事件的发送者,则 NSubstitute 会创建。

 1     [TestMethod]
 2     public void Test_RaisingEvents_ArgsDoNotHaveDefaultCtor()
 3     {
 4       var engine = Substitute.For<IEngine>();
 5 
 6       int numberOfEvents = 0;
 7       engine.LowFuelWarning += (sender, args) => numberOfEvents++;
 8 
 9       // 发送事件,并携带指定的事件参数,未指定发送者
10       engine.LowFuelWarning += Raise.EventWith(new LowFuelWarningEventArgs(10));
11       // 发送事件,并携带指定的事件参数,并指定发送者
12       engine.LowFuelWarning += Raise.EventWith(new object(), new LowFuelWarningEventArgs(10));
13 
14       Assert.AreEqual(2, numberOfEvents);
15     }

引发Delegate事件

有时事件会通过委托来声明,而没有继承自 EventHandler<> 或 EventHandler。这种事件可以通过使用 Raise.Event<TypeOfEventHandlerDelegate>(arguments)来引发。NSubstitute 会尝试和猜测该委托所需的参数,但如果没成功,NSubstitute 会告诉你具体需要提供哪个参数。

下面这个示例演示了引发 INotifyPropertyChanged 事件,该事件使用 PropertyChangedEventHandler 委托并需要2个参数。

 1     [TestMethod]
 2     public void Test_RaisingEvents_RaisingDelegateEvents()
 3     {
 4       var sub = Substitute.For<INotifyPropertyChanged>();
 5       bool wasCalled = false;
 6 
 7       sub.PropertyChanged += (sender, args) => wasCalled = true;
 8 
 9       sub.PropertyChanged += Raise.Event<PropertyChangedEventHandler>(
10         this, new PropertyChangedEventArgs("test"));
11 
12       Assert.IsTrue(wasCalled);
13     }

引发Action事件

在 IEngine 示例中,RevvedAt 事件被声明为 Action<int>。这是委托事件的另外一种形式,我们可以使用 Raise.Event<Action<int>>() 来引发该事件。

 1     [TestMethod]
 2     public void Test_RaisingEvents_RaisingActionEvents()
 3     {
 4       var engine = Substitute.For<IEngine>();
 5 
 6       int revvedAt = 0;
 7       engine.RevvedAt += rpm => revvedAt = rpm;
 8 
 9       engine.RevvedAt += Raise.Event<Action<int>>(123);
10 
11       Assert.AreEqual(123, revvedAt);
12     }

NSubstitute 完全手册

posted @ 2013-05-22 11:24  sangmado  阅读(2215)  评论(0编辑  收藏  举报