2012-07-04 14 views
5

muszę przetestować kawałek kodutestów jednostkowych IObservable <T> z ObserveOnDispatcher

 var watcher = new FakeIFileSystemWatcher(); 
     watcher.FilesToBeImported 
      .ObserveOnDispatcher() 
      .Subscribe(list.Add); 

więc stworzyłem ten mały test jednostkowy, ale nie mogę zrobić to zdać przyczyna list.Count jest zawsze 0

[Test] 
    public void Foo() 
    { 
     var list = new List<string>(); 

     var watcher = new FakeIFileSystemWatcher(); 
     watcher.FilesToBeImported 
      .ObserveOnDispatcher() 
      .Subscribe(list.Add); 

     Task task = Task.Factory.StartNew(() => 
     {     
      watcher.AddFile("cc"); 
      watcher.AddFile("cc"); 
      watcher.AddFile("cc"); 
     }, TaskCreationOptions.LongRunning); 
     Task.WaitAll(task); 

     Assert.AreEqual(3, list.Count); 
    } 

jeśli I ustosunkowania się metodę

  .ObserveOnDispatcher() 

to przejdzie, ale jak mogę dostać pracy również przestrzegać OnDispatcher()?

+0

Jaka jest wartość 'list.Count 'przy awarii? –

+0

Rozwiązałem używając klasy DispatcherUtil Znalazłem tutaj http://stackoverflow.com/questions/1106881/using-t--wpf-dispatcher-in-unit-tests – jitidea

+0

Chcę tylko zwrócić uwagę, że dzięki współbieżności (domyślnej lub explicite) w twoich testach jednostkowych, naprawdę jesteś ograniczony w tym, co możesz zrobić. Tutaj masz zarówno Zadania, jak i Dyspozytor, że nie masz żadnych "szwów", w których możesz je zastąpić podwójnym testem (mock/stub). Tak jak (zakładam) wstrzykniesz prawdziwą implementację IFileSystemWatcher w swoim kodzie prod, wstrzyknąłbyś SchedulerProvider, który dałby ci prawdziwą zgodność w testach, ale testowałeś w testach jednostkowych. Znacznie szybsze testy jednostkowe, łatwiejsze do przetestowania również inne rzeczy, np. Limity czasu. –

Odpowiedz

1

I rozwiązać przy użyciu klasy DispatcherUtil znalazłem tutaj Using the WPF Dispatcher in unit tests

teraz mój kod jest następujący

[Test] 
    public void Foo() 
    { 
     var list = new List<string>(); 

     var watcher = new FakeIFileSystemWatcher(); 
     watcher.FilesToBeImported 
      .ObserveOnDispatcher() 
      .Subscribe(list.Add); 

     Task task = Task.Factory.StartNew(() => 
     { 
      watcher.AddFile("cc"); 
      watcher.AddFile("cc"); 
      watcher.AddFile("cc"); 
      watcher.AddFile("cc"); 
     }, TaskCreationOptions.LongRunning); 
     Task.WaitAll(task); 
     DispatcherUtil.DoEvents(); 
     Assert.AreEqual(4, list.Count); 
    } 

i działa jak czar

5

Jeśli użyjesz ObserveOnDispatcher, utworzysz zależność od "dyspozytora", co oznacza, że ​​potrzebujesz okna i pętli wiadomości. Aby obejść ten problem w teście jednostkowym, można zamiast tego użyć metody ObserveOn, która używa terminarza, a następnie użyć wtyczki zależności, aby wstrzyknąć odpowiedni harmonogram. Do testowania jednostkowego można użyć Scheduler.Immediate i dla rzeczywistej aplikacji można użyć DispatcherScheduler.Instance. Zauważ, że istnieje również TestScheduler, który jest naprawdę przydatny do uruchamiania testów jednostkowych w czasie wirtualnym.

+0

Dziękuję za odpowiedź. ten wiersz kodu watcher.FilesToBeImported.ObserveOnDispatcher(). Subskrybuj (list.Add); jest w moim systemie w trakcie testu, więc nie mogę go zmienić tylko na potrzeby testu – jitidea

+3

@ scott4dev: Chodzi mi o to, że czasami trzeba zmodyfikować system w celu jego przetestowania. Na przykład. jeśli masz dostęp do bazy danych, musisz utworzyć interfejs dla bazy danych, co pozwoli ci na dostęp do bazy danych itp. Twoje rozwiązanie oczywiście tego uniknie. –

+0

masz rację, czasami musisz zmodyfikować testowany system, aby można było go przetestować, ale moim zdaniem tak nie jest. Wolę używać DispatcherUtil.DoEvents(); w moich testach i pozwól mojej SUT w oryginalnym stanie – jitidea

0

Można spróbować wywołać metodę jak to:

var dispatcher = Application.Current != null ? Application.Current.Dispatcher : Dispatcher.CurrentDispatcher; 

dispatcher.Invoke((Action)(() => YourMethodToTest()); 
Powiązane problemy