2011-06-29 118 views
6

我正在使用NUnit和Moq來測試一個有一些事件的類,我試圖找到測試事件是否被觸發的最佳方法。我想出了這個解決方案,但它感覺有點骯髒,因爲我必須爲測試創建一個接口。任何方式,我可以做更少的代碼相同的事情,或不必創建一個接口?使用NUnit和Moq單元測試事件的更好方法?

它並不壞,但我覺得有人可能有更好的解決方案。 任何想法表示讚賞。 謝謝。

[Test] 
    public void StartedAndStoppedEventsShouldFireWhenStartedAndStopped() 
    { 
     var mockStartedEventSubscriber = new Mock<IEventSubscriber>(); 
     var mockStoppedEventSubscriber = new Mock<IEventSubscriber>(); 

     _NetworkMonitor.Started += mockStartedEventSubscriber.Object.Handler; 
     _NetworkMonitor.Stopped += mockStoppedEventSubscriber.Object.Handler; 

     _NetworkMonitor.Start(); 
     _NetworkMonitor.Stop(); 

     Func<bool> func =() => { return (eNetworkMonitorStatus.Stopped == _NetworkMonitor.Status); }; 
     Utilities.WaitUntilTrue(func, _NetworkMonitor.Interval * 2, 10); 

     _NetworkMonitor.Started -= mockStartedEventSubscriber.Object.Handler; 
     _NetworkMonitor.Stopped -= mockStoppedEventSubscriber.Object.Handler; 

     mockStartedEventSubscriber.Verify(h => h.Handler(_NetworkMonitor, EventArgs.Empty), Times.Once()); 
     mockStoppedEventSubscriber.Verify(h => h.Handler(_NetworkMonitor, EventArgs.Empty), Times.Once()); 
    } 

    public interface IEventSubscriber 
    { 
     void Handler(object sender, EventArgs e); 
    } 

回答

4

這個測試似乎更容易做,而不嘲笑。使測試夾具成爲事件訂戶的雙重身份。

_networkMonitor.Started += this.SetStartedFlag; // a private method which sets a flag in the test fixture. 
_networkMonitor.Start(); 
Assert.That(StartedFlag, Is.True); 
+0

我將不得不爲每個我正在測試的事件創建一個新標誌和新方法。這會增加相當大的膨脹。在這個例子中,我可以使用相同的接口。但我明白你在說什麼。 –

+0

@Dusty Lau - 您可以使用通用標誌(NotificationReceived)和處理程序,因爲您要測試的只是該事件被觸發。如果您正在測試一個界面,例如INotifyPropertyChanged,你可以編寫一個工具類PropertyChangeListener,它可以與接口的任何實現一起工作。 – Gishu

0

下面是我過去使用過的方法的一個片段,以取得良好效果。它只是在每次事件被觸發時將(在我的情況下)ConnectionChangedEventArgs的實例添加到列表<>。然後斷言有多少事件被觸發。如果你願意的話,希望你明白這個想法,並且可以根據自己的需要進行調整。

[Test] 
public void GoodConnectionRaisesConnectionChangedEvent() 
{ 
    const int EXPECTED = 1; 
    List<ConnectionChangedEventArgs> ev = new List<ConnectionChangedEventArgs>(); 

    // Mocks and setup stuff here... 

    using (PlcController pc = new PlcController(mock.Object)) 
    { 
     pc.ConnectionChanged += delegate(object sender, ConnectionChangedEventArgs e) 
     { 
      ev.Add(e); 
     }; 

     pc.Connect(); 
    } 

    Assert.That(ev.Count, Is.EqualTo(EXPECTED)); 
} 
+0

我可以處理的投票,但請評論爲什麼! – Andy

3

我想,你根本就不需要moq。你可以註冊這些事件並評估它們是否已被解僱(或解僱他們的次數):

public class NetworkMonitor 
    { 
     public event EventHandler Started; 
     public event EventHandler Stopped; 

     public void Start() 
     { 
      var handler = Started; 
      if (handler != null) 
       handler(this, EventArgs.Empty); 
     } 

     public void Stop() 
     { 
      var handler = Stopped; 
      if (handler != null) 
       handler(this, EventArgs.Empty); 
     } 

    } 

    [Test] 
    public void StartedAndStoppedEventsShouldFireWhenStartedAndStopped() 
    { 

     NetworkMonitor classUnderTest = new NetworkMonitor(); 
     bool startedWasFired = false; 
     int stoppedWasFired = 0; 
     classUnderTest.Started += (o, e) => { startedWasFired = true; }; 
     classUnderTest.Stopped += (o, e) => { stoppedWasFired++; }; 

     classUnderTest.Start(); 
     Assert.That(startedWasFired); 
     classUnderTest.Stop(); 
     Assert.That(stoppedWasFired, Is.EqualTo(1)); 
    }