2012-07-04 21 views
5

Tôi cần phải kiểm tra đoạn mãĐơn vị kiểm tra IObservable <T> với ObserveOnDispatcher

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

vì vậy tôi tạo thử nghiệm đơn vị nhỏ này nhưng tôi không thể làm cho nó vượt qua nguyên nhân list.Count luôn là 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); 
    } 

nếu tôi nhận xét ra phương pháp

  .ObserveOnDispatcher() 

nó vượt qua nhưng làm thế nào tôi có thể lấy nó làm việc cũng với quan sát OnDispatcher()?

+0

Giá trị của 'list.Count là gì 'thất bại? –

+0

Tôi đã giải quyết bằng cách sử dụng lớp DispatcherUtil Tôi tìm thấy ở đây http://stackoverflow.com/questions/1106881/using-the-wpf-dispatcher-in-unit-tests – jitidea

+0

Tôi chỉ muốn chỉ ra rằng bằng cách có đồng thời (ẩn hoặc rõ ràng) trong các bài kiểm tra đơn vị của bạn, bạn thực sự bị giới hạn trong những gì bạn có thể làm. Ở đây bạn có cả Tasks và Dispatcher mà bạn đã cung cấp không có 'seams', trong đó bạn có thể thay thế chúng cho một test double (mock/stub). Cũng giống như (tôi giả sử) bạn tiêm một thực hiện thực tế của IFileSystemWatcher trong mã prod của bạn, bạn sẽ tiêm một SchedulerProvider đã cho bạn concurreny thực trong prod nhưng kiểm tra lên lịch trong các bài kiểm tra đơn vị bạn. Kiểm tra đơn vị nhanh hơn nhiều, dễ dàng hơn để kiểm tra những thứ khác như timeouts vv quá. –

Trả lời

1

tôi giải quyết bằng cách sử dụng lớp DispatcherUtil tôi tìm thấy ở đây Using the WPF Dispatcher in unit tests

tại mã của tôi là sau

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

và nó hoạt động như một nét duyên dáng

5

Nếu bạn sử dụng ObserveOnDispatcher bạn tạo phụ thuộc vào "điều phối" có nghĩa là bạn cần cửa sổ và vòng lặp tin nhắn. Để giải quyết vấn đề này trong một bài kiểm tra đơn vị, bạn có thể sử dụng phương thức ObserveOn sử dụng một trình lập lịch biểu và sau đó sử dụng tiêm phụ thuộc để chèn đúng trình lên lịch biểu. Đối với thử nghiệm đơn vị, bạn có thể sử dụng Scheduler.Immediate và cho ứng dụng thực tế bạn có thể sử dụng DispatcherScheduler.Instance. Lưu ý rằng cũng có một TestScheduler thực sự hữu ích cho việc chạy thử nghiệm đơn vị trong thời gian ảo.

+0

Cảm ơn bạn đã trả lời. dòng dõi mã này.FilesToBeImported.ObserveOnDispatcher(). Đăng ký (list.Add); là trong hệ thống của tôi được kiểm tra vì vậy tôi không thể thay đổi nó chỉ cho thử nghiệm – jitidea

+3

@ scott4dev: quan điểm của tôi là đôi khi bạn phải sửa đổi hệ thống của bạn được thử nghiệm để làm cho nó có thể kiểm tra được. Ví dụ. nếu bạn truy cập cơ sở dữ liệu, bạn phải tạo một giao diện cho cơ sở dữ liệu cho phép bạn truy cập cơ sở dữ liệu, vv. Giải pháp của bạn tránh điều này tất nhiên. –

+0

bạn là đúng, đôi khi phải sửa đổi hệ thống của bạn được thử nghiệm để làm cho nó đơn vị testable nhưng theo ý kiến ​​của tôi điều này không phải là trường hợp. Tôi thích sử dụng DispatcherUtil.DoEvents(); trong các thử nghiệm của tôi và cho phép SUT của tôi ở trạng thái ban đầu – jitidea

0

Bạn có thể thử để gọi phương pháp của bạn như này:

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

dispatcher.Invoke((Action)(() => YourMethodToTest());