2011-01-24 3 views
4

단위 테스트 가능으로하고 싶은 MVVM-Lite 애플리케이션이 있습니다. 모델은 System.Timers.Timer를 사용하므로 update 이벤트는 백그라운드 작업자 스레드에서 끝납니다. 이 단위 테스트를 거쳤지 만 런타임에 System.NotSupportedException이 발생했습니다. "이 유형의 CollectionView는 Dispatcher 스레드와 다른 스레드에서 해당 SourceCollection에 대한 변경을 지원하지 않습니다." MVVM-lite 클래스 Threading.DispatcherHelper가 문제를 해결할 것이라고 기대했지만 DispatcherHelper.CheckBeginInvokeOnUI를 호출하면 유닛 테스트가 실패합니다. 여기에 내가 http://kentb.blogspot.com/2009/04/mvvm-infrastructure-viewmodel.html의 트릭하지만 Dispatcher.CurrentDispatcher에 호출 할 수있는 전화를 시도했다 뷰 모델단위 테스트 할 수있는 MVVM 코드에서 Dispatcher 사용

private void locationChangedHandler(object src, LocationChangedEventArgs e) 
{ 
    if (e.LocationName != this.CurrentPlaceName) 
    { 
     this.CurrentPlaceName = e.LocationName; 
     List<FileInfo> filesTaggedForHere = Tagger.FilesWithTag(this.CurrentPlaceName); 

     //This nextline fixes the threading error, but breaks it for unit tests 
     //GalaSoft.MvvmLight.Threading.DispatcherHelper.CheckBeginInvokeOnUI(delegate { updateFilesIntendedForHere(filesTaggedForHere); }); 

     if (Application.Current != null) 
     { 
      this.dispatcher.Invoke(new Action(delegate { updateFilesIntendedForHere(filesTaggedForHere); })); 
     } 
     else 
     { 
      updateFilesIntendedForHere(filesTaggedForHere); 
     } 
    } 
} 
private void updateFilesIntendedForHere(List<FileInfo> filesTaggedForHereIn) 
{ 
    this.FilesIntendedForHere.Clear(); 
    foreach (FileInfo file in filesTaggedForHereIn) 
    { 
     if (!this.FilesIntendedForHere.Contains(file)) 
     { 
      this.FilesIntendedForHere.Add(file); 
     } 
    } 
} 

에서 함께 결국 한 코드 것은 단위 테스트 중에 실행하지 못했습니다 때문에 실패했습니다. 그래서 실행이 응용 프로그램이 아닌 테스트에 있다면 헬퍼 메서드를 직접 호출하는 것입니다.

이것은 옳지 않을 수 있습니다. ViewModel은 어디에서 호출되는지 상관하지 않아야합니다. 아무도 왜 켄트 Boogaart의 발송자 방법도 MVVM - 라이트 DispatcherHelper.CheckBeginInvokeOnUI 내 단위 테스트에서 작동 볼 수 있습니까?

답변

1

나는 이런 식으로 작업을 수행합니다

class MyViewModel() { 
    private readonly SynchronizationContext _syncContext; 

    public MyViewModel() { 
     _syncContext = SynchronizationContext.Current; // or use DI 
    ) 

    ... 

    public void SomeTimerEvent() { 
     _syncContext.Post(_ => UpdateUi(), null); 
    } 
} 

기본 컨텍스트는 UI에서 테스트 및 디스패처의 스레드 될 것입니다. 다른 동작을 원하면 자체 테스트 컨텍스트를 쉽게 만들 수도 있습니다.

0

MVVM-lite에서 쉽게 대답 할 수 있다고 생각하지 않습니다. DispatcherHelper.CheckBeginInvokeOnUI를 호출하는 올바른 솔루션이 있습니다. 그러나 단원 테스트가 실행 중일 때 UI가 존재하지 않고 DispatcherHelper가 제대로 실행되지 않습니다.

나는 ReactiveUI을 사용합니다. DispatcherHelper.CheckBeginInvokeOnUI (RxApp.DeferredScheduler) 버전은 단위 테스트에서 실행 중인지 확인합니다. 그럴 경우 존재하지 않는 UI 스레드에 마샬링을 시도하는 대신 현재 스레드에서 실행됩니다. 이 코드를 사용하여 DispatcherHelper에 자신 만의 체크를 작성할 수 있습니다. 관련 코드는 RxApp.cs 메서드 InUnitTestRunner() (줄 196)에 있습니다. 그것은 꽤 해키지만 작동하지만 더 좋은 방법은 없다고 생각합니다.

0

그냥 내 ViewModelUnitTestBase의 Initialize 메서드를 호출하면 제대로 작동합니다. DispatcherHelper.UIDispatcher가 null이 아닌지 확인하십시오.

public abstract class ViewModelUnitTestBase<T> where T : ViewModelBase 
{ 
    private T _viewModel = default(T); 
    public T ViewModel 
    { 
     get { return _viewModel; } 
     set { _viewModel = value; } 
    } 

    static ViewModelUnitTestBase() 
    { 
     DispatcherHelper.Initialize(); 
    } 
} 
관련 문제