2013-12-17 42 views
1

我試圖對一個在單獨的線程上做一些事情的類運行單元測試,然後通知父母它已經完成了使用事件處理程序的任務。這是我的測試代碼:掛鉤到單元測試內的事件

 [TestMethod()] 
    public void InitTest() 
    { 
     Controller target = new Controller(); 
     target.FinishedCommand += delegate(bool success) 
     { 
      Assert.AreEqual(true, success); 
     }; 
     target.Init(); 
     while (true) 
     { 

     } 
    } 

這是我測試的方法:

public delegate void ControllerEventHandler(bool success); 
public class Controller 
{ 
    public event ControllerEventHandler FinishedCommand; 
    public void Init() 
    { 
     FinishedCommand(true); 
    } 
} 

我意識到的init()不使用一個新的線程,但我只是想確保測試正在運行。測試只是永遠停留在while()循環中,而匿名委託從不輸入。

活動連接不正確?在單元測試中可以像這樣使用事件嗎?

回答

1

事件可以測試,但我發現的最好的方法是使用ManualResetEvent。考慮這個修改:

public void InitTest() 
{ 
    Controller target = new Controller(); 
    target.FinishedCommand += delegate(bool success) 
    { 
     Assert.AreEqual(true, success); 
     eventRaised.Set(); 
    }; 

    ManualResetEvent eventRaised = new ManualResetEvent(false); 
    target.Init(); 

    eventRaised.WaitOne(); 
} 

這裏會發生什麼事是WaitOne將停止此方法的執行等待Set()被調用。由於Set()在事件處理程序中被調用,所以它在邏輯上等待,直到事件被引發和聲明。

但是,你將不得不將您Assert事件處理程序之外,因爲該方法,否則不會成功,所以需要一個更細微的修改:

public void InitTest() 
{ 
    bool succeeded = false; 
    Controller target = new Controller(); 
    target.FinishedCommand += delegate(bool success) 
    { 
     succeeded = success; 
     eventRaised.Set(); 
    }; 

    ManualResetEvent eventRaised = new ManualResetEvent(false); 
    target.Init(); 

    eventRaised.WaitOne(); 
    Assert.IsTrue(succeeded); 
} 
+0

感謝。我的例子實際上並沒有使用單獨的線程,但我會實現這一點,並且您的答案很有幫助。 – user2445507

2

Assert不會停止測試和測試不會失敗,因爲Assert語句沒有執行 - 因此while(true)循環會阻止您的測試結束。

此外,事件類似於簡單的方法調用 - 所以在target.Init();返回之前,事件已經發生。

你應該使用一個變量bool eventOccurredAndSucceeded = false,你可以在事件處理程序中設置,並調用target.Init();後簡單地測試了:

[TestMethod()] 
    public void InitTest() 
    { 
     bool eventOccurredAndSucceeded = false; 
     Controller target = new Controller(); 
     target.FinishedCommand += delegate(bool success) 
     { 
      if (success) 
      { 
       eventOccurredAndSucceeded = true; 
      } 
     }; 

     target.Init(); 
     Assert.AreEqual(true, eventOccurredAndSucceeded); 
    } 
+0

所以在這裏,* not *利用'ManualResetEvent'類的問題是存在競爭條件,在這種競爭條件下,測試有時會成功並失敗。 –

+0

@MichaelPerrenoud我在這裏看不到多個線程? –

+0

你可能是正確的。 'ManualResetEvent'在這裏可能不需要,因爲'Init'直接引發事件。 –