2016-06-28 45 views
1

我發現了幾個Stack Overflow問題以及一些已經涉及這個主題的博客帖子,但不幸的是他們中沒有一個能夠滿足我的需求。我將從一些示例代碼開始,展示我想要完成的任務。如何測試使用DispatcherTimer的類?

using System; 
using System.Security.Permissions; 
using System.Threading.Tasks; 
using System.Windows.Threading; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace MyApp 
{ 
    [TestClass] 
    public class MyTests 
    { 
     private int _value; 

     [TestMethod] 
     public async Task TimerTest() 
     { 
      _value = 0; 
      var timer = new DispatcherTimer {Interval = TimeSpan.FromMilliseconds(10)}; 
      timer.Tick += IncrementValue; 
      timer.Start(); 

      await Task.Delay(15); 
      DispatcherUtils.DoEvents(); 
      Assert.AreNotEqual(0, _value); 
     } 

     private void IncrementValue(object sender, EventArgs e) 
     { 
      _value++; 
     } 
    } 

    internal class DispatcherUtils 
    { 
     [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
     public static void DoEvents() 
     { 
      var frame = new DispatcherFrame(); 
      Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrame), frame); 
      Dispatcher.PushFrame(frame); 
     } 

     private static object ExitFrame(object frame) 
     { 
      ((DispatcherFrame)frame).Continue = false; 
      return null; 
     } 
    } 
} 

此代碼工作正常,如果,而不是使用DispatcherTimer,我使用普通的Timer。但是DispatcherTimer從不開火。我錯過了什麼?我需要什麼來激發它?

+0

我想你需要將SynchronizationContext設置爲DispatcherSynchronizationContext的一個實例。否則,在等待的另一邊,你正在一個新的線程,將有一個新的調度器,這不是你想要處理事件。 –

回答

3

如果你可以在你的系統中避免DispatcherTimer,並且使用抽象代替(Rx有一個很好的叫做IScheduler),那麼最好。這種抽象允許您明確地控制單元測試中的時間流程,而不是讓您的測試以CPU時序爲條件。

但是,如果您現在只對單元測試感興趣,那麼您需要創建一個STA線程,以確保消息傳輸安裝了合適的Dispatcher。所有「在調度程序上運行此代碼」操作只是將代理包裝在Win32消息中,並且如果您沒有Win32消息泵循環 a Dispatcher之前創建計時器),那麼這些消息將贏得'將被處理。

要做到這一點,最簡單的方法是使用WpfContexthere

[TestMethod] 
public async Task TimerTest() 
{ 
    await WpfContext.Run(() => 
    { 
    _value = 0; 
    var timer = new DispatcherTimer {Interval = TimeSpan.FromMilliseconds(10)}; 
    timer.Tick += IncrementValue; 
    timer.Start(); 

    await Task.Delay(15); 
    Assert.AreNotEqual(0, _value); 
    }); 
} 

同樣,這種方法是不合格的,因爲它取決於時機。因此,如果您的防病毒軟件感到不安並決定檢查您的單元測試,它可能會虛假失敗。像IScheduler這樣的抽象實現了可靠的單元測試。

+0

優秀的答案。非常感謝你爲所有增加的細節。 – SoaperGEM

相關問題