2016-06-28 44 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

相关问题