2012-03-22 68 views
4

我有一個具有公共方法Start,一個私有方法和一個事件Finishing類。 Start致電new Thread(private_method)。使用事件的私有方法返回值。當這個方法完成他們的工作,然後調用這個事件。測試方法(NUnit的2.6)

現在我想寫測試此類。如果我這樣寫:

[Test] 
    public void Test1() 
    { 
     SomeClass someObject = new SomeClass(); 

     someObject.Finishing += new SomeClass.FinishingEventHandler((sender, a) => 
     { 
      Assert.True(false); 
     }); 
     someObject.Start(); // when this method will finish, then call event Finishing 
    } 

它應該是失敗,但事實並非如此。我認爲方法Test1在事件發生之前完成。那麼,我該如何測試這些代碼呢?如何測試方法,它創建一個新的線程,並導致我們從事件

回答

16

NUnit有內置的功能來等待斷言。這就是所謂的 '後':

[Test] 
public void ShouldRaiseFinishedEvent() 
{ 
    SomeClass someObject = new SomeClass(); 
    bool eventRaised = false; 
    someObject.SomethingFinished += (o, e) => { eventRaised = true; }; 

    someObject.DoSomething(); 
    Assert.That(eventRaised, Is.True.After(500)); 
} 
+0

不知道,我使用FluentAssertions而不是內置的NUnit斷言。剛剛檢查出來,他們有一些事件監測斷言。 http://fluentassertions.codeplex.com/documentation – Bronumski 2012-03-22 23:22:56

+0

內置等待相當不錯。它允許定義超時和輪詢間隔Is.EqualTo(「完成」)。(500,50)之後。所以你不需要等很長時間,如果事情發生很快:) – 2012-03-22 23:26:17

+0

這個解決方案看起來很不錯,但..我有這個問題。我不確定發生了什麼。在我的例子中'eventRaised'被正確設置爲'true'(我把它寫在控制檯上)。但是'斷言。(事件發生了,Is.True.After(5000))';' 「告訴我」'eventRaised'是'false' ..怎麼可能?我不確定,但也許它是'bool'的問題,它不是引用類,所以也許'Assert.That()'獲得這個'eventRaised'就像false,並且它不引用'eventRaised'我在'event'設置爲'true' .. – nirmus 2012-03-23 01:31:06

1

你是對的獲得。

首先,NUnit的和它的各種主機環境已經或者還有,各種缺陷和限制線程測試中開始。尤其是,如果在測試執行完成之前不確定線程​​是否完成,那麼NUnit不知道有人正在執行代碼,在測試返回後它將卸載。我經常記住這種模式,當通過Resharper集成來執行NUnit時,會定期導致VS崩潰,以及偶爾出現的與NUnit一起提供的GUI和控制檯運行程序的故障和內存泄漏。

這就是說,你需要確保兩件事情。

  1. 通過連接所產生的所有線程來實現測試環境的基本安全。
  2. 僅在主線程中拋出指示測試失敗的所有異常。這意味着後臺線程必須將其結果傳遞給主線程,並且該線程必須完成所有各種不變量。

更好的是,構造您的代碼,以便您可以在沒有後臺線程的情況下進行單元測試 - 如果可能的話。

+0

感謝解釋。我以爲我的老師告訴我使用NUnit,因爲它是非常好的框架..我錯了;) – nirmus 2012-03-22 22:49:41

+0

@nirmus - 不,NUnit絕對好!但* unit *測試背後的想法是,您理想地測試非常小的代碼塊(單位)。大集成測試也是可能的,但它必須是獨立的。如果你做出了一些動作,你也應該在測試中停下來,這樣它就是自成一體的。 NUnit不知道你做了什麼。 – 2012-03-22 23:00:48

0

如前所述,你可以單元測試多線程的組件,但它不乾淨像普通的單元測試。我主要在驗收測試中遇到過這個問題,並且在.net 4 TaskParallel類別中取得了巨大成功。然而,在這種情況下,簡單的睡眠可能會讓你去,但如果你開始做很多這些測試,你可能需要一個更高效的方式來做到這一點。

[Test] 
public void Test1() 
{ 
    bool wasCalled = false; 

    SomeClass someObject = new SomeClass(); 

    someObject.Finishing += new SomeClass.FinishingEventHandler((sender, a) => 
    { 
     wasCalled = true; 
    }); 
    someObject.Start(); // when this method will finish, then call event Finishing 

    Thread.Sleep(2000); 

    Assert.True(wasCalled); 
} 

你做什麼都需要一些超時的地方,會導致測試來完成的,而不是永遠掛,這可能在測試本身或一些測試庫完成有Timeout屬性你可以裝飾測試用。

1
[Test] 
public void ShouldRaiseFinishedEvent() 
{ 
    SomeClass someObject = new SomeClass(); 
    AutoResetEvent eventRaised = new AutoResetEvent(false); 
    someObject.SomethingFinished += (o, e) => { eventRaised.Set(); }; 

    someObject.DoSomething(); 
    Assert.IsTrue(eventRaised.WaitOne(TimeSpan.FromMilliseconds(500))); 
} 

這應該工作