我有一個包含這樣的異步調用的方法:如何對包含異步調用的方法進行單元測試?
public void MyMethod() {
...
(new Action<string>(worker.DoWork)).BeginInvoke(myString, null, null);
...
}
我使用的是統一和創建模擬對象是沒有問題的,但我怎麼能測試的DoWork稱爲無需擔心競爭條件?
A previous question提供了一個解決方案,但在我看來,等待句柄是一種破解(競爭條件仍然存在,儘管實際上不可能提高)。
編輯:好的,我想我會問這個問題的一個非常普遍的方式,但似乎我不得不進一步闡述這個問題:
我想創建上述測試的MyMethod,所以我做這樣的事情:
[TestMethod]
public void TestMyMethod() {
...setup...
MockWorker worker = new MockWorker();
MyObject myObj = new MyObject(worker);
...assert preconditions...
myObj.MyMethod();
...assert postconditions...
}
天真的方法是創建一個MockWorker(),簡單地設置一個當DoWork的被稱爲標誌,並測試該標誌在後置條件。這當然會導致競爭條件,在MockWorker中設置標誌之前檢查後置條件。
更正確的做法(這我可能會最終使用)使用等待句柄:
...並使用以下斷言:
Assert.IsTrue(worker.AutoResetEvent.WaitOne(1000, false));
這是這很好......但在理論下面可能會發生:
- 在我的DoWork代理上調用BeginInvoke
- 由於某些原因,主線程或DoWork線程的執行時間均爲1000毫秒。
- 主線程被賦予執行時間,並且由於超時斷言失敗,即使DoWork線程尚未執行。
我誤解了AutoResetEvent的工作原理嗎?我只是太偏執,還是有一個聰明的解決方案來解決這個問題?
你能解釋一下這種情況下的比賽狀況嗎?這幾乎是我使用的解決方案,它永遠不會讓我失望。 – 2009-02-18 15:05:10
不,我相信它永遠不會失敗,因爲競爭條件主要是理論上的。 競爭條件很簡單:如果由於某種原因,工作線程在超時之前從未被賦予執行時間,則測試錯誤地失敗。 我知道!這是猜測性的,但我知道墨菲定律;-) – toxvaerd 2009-02-18 15:26:10
我見過使用這些標誌的測試會在重負載的構建服務器上失敗(需要重建以增加負載)。走信號路線並使用暫停對我來說似乎更好。另外,使用標誌意味着你必須在整個一段時間內進入睡眠狀態,這可能會讓你的測試套件花費很多時間才能運行。 – 2009-05-09 19:32:04