2016-06-28 6 views
1

私はすでにこの話題に触れるのブログの記事のカップルと一緒にスタックオーバーフローの質問のカップルを見つけたが、残念ながらそれらのどれも私のニーズを満たしていません。私は何を達成したいのかを示すサンプルコードから始めます。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

私はあなたがDispatcherSynchronizationContextのインスタンスへのSynchronizationContextを設定する必要があると思います。それ以外の場合は、イベントの処理を希望する新しいディスパッチャを持つ新しいスレッドが待機しています。 –

答えて

3

テスト中のシステムにDispatcherTimerが表示されないようにして、代わりに抽象化を使用するとよい(RxはISchedulerと呼ばれる素晴らしいものがあります)。この種の抽象化によって、CPUタイミングで条件をテストするのではなく、単体テストで時間の流れを明示的に制御することができます。

単体テストに興味があれば、のメッセージをポンピングするSTAスレッドを作成し、適切なDispatcherを持っている必要があります。 Win32メッセージでデリゲートをラップするだけで、ループをポンピングするWin32メッセージがない場合は、Dispatcherの前にタイマーを作成)というメッセージが表示され、処理される。

これを行う最も簡単な方法は、hereからWpfContextを使用することです:

[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

関連する問題