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

SynchronizationContext를 DispatcherSynchronizationContext의 인스턴스로 설정해야한다고 생각합니다. 그렇지 않으면 반대편에서 이벤트를 처리하려는 새 디스패처가없는 새 스레드에 있습니다. –

답변

3

테스트중인 시스템에서 DispatcherTimer을 피하고 추상화를 사용하는 것이 가장 좋습니다 (RX는 멋진 번호 IScheduler). 이러한 종류의 추상화를 통해 CPU 타이밍에 대한 조건부 테스트가 아닌 단위 테스트에서 시간 흐름을 명시 적으로 제어 할 수 있습니다.

하지만 지금 단위 테스트에만 관심이있는 경우 메시지 펌핑에 적절한 Dispatcher이있는 STA 스레드를 만들어야합니다. "디스패처에서이 코드를 실행하십시오"작업은 Win32 메시지에서 대리자를 래핑하고 Win32 메시지 펌핑 루프가 인 경우Dispatcher (전에 타이머를 작성하기 전에) 처리해야합니다. 이 타이밍에 의존하기 때문에

[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); 
    }); 
} 

다시 말하지만, 이런 종류의 접근법이 이하의 것입니다 :

이 작업을 수행하는 가장 쉬운 방법은 WpfContexthere에서 사용하는 것입니다. 따라서 바이러스 백신이 화가 나서 유닛 테스트를 검사하기로 결정한 경우 위장적으로 실패 할 수 있습니다. IScheduler과 같은 추상화를 통해 신뢰할 수있는 단위 테스트가 가능합니다.

+0

우수 답변. 모든 추가 된 세부 사항에 대해 정말 고마워. – SoaperGEM