2016-06-28 9 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, я использую обычный таймер. Но DispatcherTimer никогда не срабатывает. Что мне не хватает? Что мне нужно, чтобы заставить его стрелять?

+0

Я думаю, вам нужно установить SynchronizationContext для экземпляра DispatcherSynchronizationContext. В противном случае с другой стороны ждут, что вы находитесь в новом потоке, у которого будет новый диспетчер, который не тот, для которого вы хотите обработать события. –

ответ

3

Лучше всего, если вы можете избежать DispatcherTimer в своей тестируемой системе и вместо этого использовать абстракцию (у Rx есть хороший номер, называемый IScheduler). Такая абстракция позволяет вам явно контролировать поток времени в ваших модульных тестах, а не делать ваши тесты условными для таймингов CPU.

Но если вы просто заинтересованы в модульном тестировании на данный момент, то вам нужно создать STA поток, который делает сообщение насосным и имеют собственные Dispatcher установлено. Все операции «запускать этот код в диспетчере» просто завершают делегат в сообщении Win32, и если у вас нет сообщения о пересылкесообщения 0 0 0 t обрабатываться.

Самый простой способ сделать это состоит в использовании WpfContext из here:

[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

 Смежные вопросы

  • Нет связанных вопросов^_^