2017-04-12 29 views
0

我已經上傳了一些代碼在git集線器,可以在這裏找到: https://github.com/Shaunus87/SyncTest其中包括我的原型代碼和我的單元測試它。單元測試同步代碼有競爭條件?

我基本上宣告我的同步碼,掛鉤事件,調用最終會調用事件的方法,並斷言該事件是否被稱爲與否:

 bool called = false; 

     var testBinsToVend = GetRoboBins(); 
     var vendHelper = new VendingHelper(null, testBinsToVend, VendType.Issue); 

     vendHelper.Complete += delegate() { 
      called = true; 
     }; 

     vendHelper.DoVending(); 

     Assert.IsTrue(called); 

所有的代碼是同步的(如據我所知),但如果我運行測試失敗,如果我通過它進行調試,它會通過...

我已經嘗試了幾件事情,它似乎或者a)我的代碼是祕密異步和我有一個競爭條件或b)當運行代碼時,它決定不執行一半的事件?

到底是什麼?

編輯: 我也試着設置一個手動重置事件象下面這樣:

 bool called = false; 
     var done = new ManualResetEvent(false); 

     var testBinsToVend = GetRoboBins(); 
     var vendHelper = new VendingHelper(null, testBinsToVend, VendType.Issue); 

     vendHelper.Complete += delegate() { 
      called = true; 
      done.Set(); 
     }; 

     vendHelper.DoVending(); 

     done.WaitOne(); 
     Assert.IsTrue(called); 
     //was complete called? 
     Assert.AreEqual(true, vendHelper.Bins.All(x => x.State != VendState.Pending)); 

但因爲它是執行一條線,當done.WaitOne();被擊中測試永遠不會到達Assert.IsTrue(called);線。

+2

我在那裏發現了對'System.Threading.Timer'的引用,你確定**你的代碼是同步的嗎?該事件從哪裏開始?在[Timer_Tick]裏面(https://github.com/Shaunus87/SyncTest/blob/master/eVendVendingMachines/BaseVendingMachine.cs#L182)?在這個'called = true;'行放置一個斷點並檢查調用堆棧,這可能會告訴你在調試過程中需要知道的一切。 –

回答

2

有沒有在你的業務邏輯的問題:

private CommCommand GetLastCommand(List<CommCommand> cmds, DateTime since) { 
return cmds.Where(x => x.DateTime > since) 
      .OrderByDescending(x => x.DateTime) 
      .FirstOrDefault(); 
} 

DateTime.Now只有默認情況下爲約20毫秒左右的分辨率。這意味着您的郵件在DateTime > since之前很久纔會收到。當您逐步完成代碼時,時間會得到調整 - Send在原始接收之後發生很長時間。

您不能依賴DateTime.Now進行消息排序。它根本沒有足夠的準確性。如果您真的認爲您可以依賴發送和接收訂單的順序(也就是說,機器在提示之前從未回覆),請用簡單的計數器替換它。

+0

是的!我正要問你如何認爲我應該訂購它,然後看到你的編輯彈出。非常感謝你,我不知道DateTime對於那樣的東西是不準確的。你是怎麼發現DateTimes是問題的? (我一直在敲我的頭,認爲這是一個競爭條件>。) – Smithy

+1

@Smithy那麼,首先我在完整的處理程序中放置一個斷點 - 所以我現在確實沒有被調用。然後我確信測試在有機會運行之前沒有結束,只是因爲有一個異步問題。然後我檢查了處理程序是否應該被調用,並追蹤哪些你期望提出的。然後我檢查了前提條件,並在發送消息時打印出來('Debug.WriteLine'很有用)。最後,我在FET的WorkOnResponse中放置了一個斷點(上一次正常工作的命令),並且看到'lastRecCmd'爲空... – Luaan

+1

@Smithy ...'receivedCommands'不爲空,確實包含預期的最後一個響應。其中明確指出'GetLastCommand'是錯誤的 - 當我看到'DateTime'比較時,我不需要進一步挖掘。調試是一個藝術:D – Luaan