2012-02-17 17 views
5

Tôi đang cố gắng làm theo các đề xuất từ ​​Using the WPF Dispatcher in unit tests để chạy thử nghiệm nUnit của mình.Phương pháp đúng để sử dụng Bộ điều phối WPF trong các bài kiểm tra đơn vị

Khi tôi viết bài kiểm tra đơn vị của tôi như dưới đây, nó hoạt động:

[Test] 
public void Data_Should_Contain_Items() 
{ 
    DispatcherFrame frame = new DispatcherFrame(); 
     PropertyChangedEventHandler waitForModelHandler = delegate(object sender, PropertyChangedEventArgs e) 
     { 
      if (e.PropertyName == "Data") 
      { 
      frame.Continue = false; 
      } 
     }; 
    _myViewModel.PropertyChanged += waitForModelHandler; 
    Dispatcher.PushFrame(frame); 

    Assert.IsTrue(_myViewModel.Data.Count > 0, "Data item counts do not match"); 
} 

Tuy nhiên, nếu tôi cố gắng sử dụng các gợi ý của DispatcherUtil, nó không hoạt động:

[Test] 
public void Data_Should_Contain_Items() 
{ 
    DispatcherUtil.DoEvents(); 
    Assert.IsTrue(_myViewModel.Data.Count > 0, "Data item counts do not match"); 
} 

public static class DispatcherUtil 
{ 
    [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
    public static void DoEvents() 
    { 
     DispatcherFrame 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; 
    } 
} 

Khi tôi đang sử dụng DispatcherUtil, có vẻ như lệnh gọi ExitFrame xảy ra quá sớm, trước khi dữ liệu sẵn sàng.

Tôi có đang sử dụng DispatcherUtil chính xác không? Nó có vẻ như là một phương pháp tốt hơn để sử dụng để xử lý các điều phối thay vì sau đó chờ đợi cho callbacks từ mô hình xem.

+0

Bạn đang cố gắng để kiểm tra, chỉ nếu PropertyChangedEventHandler được gọi cho thuộc tính "dữ liệu"? Nếu vậy tại sao bạn cần phải liên quan đến điều phối viên? Tôi cũng không sử dụng _myViewModel ngoài để đính kèm trình xử lý. – Phil

+0

@Phil: Khi _myViewModel được khởi tạo, hàm tạo của nó thực hiện cuộc gọi asyn. Khi cuộc gọi đó hoàn tất, _myViewModel.Data sẽ có một số giá trị. Tôi đang cố gắng để kiểm tra rằng dữ liệu là trong thực tế dân cư, nhưng thực tế là dữ liệu được dân cư như là kết quả của một cuộc gọi asyn là những gì đang gây ra cho tôi một số rắc rối. Tôi muốn tránh phải nghe các sự kiện PropertyChanged trong bất kỳ bài kiểm tra đơn vị nào có thể phải đối phó với Dispatcher. – Flack

Trả lời

7

Vì người điều phối có vấn đề trong các bài kiểm tra đơn vị, giải pháp của tôi sẽ là phá vỡ sự phụ thuộc của mô hình xem của bạn trên người điều phối. Tôi cho rằng tài liệu tham khảo hiện tại bạn đã mã hoá cứng như:

Dispatcher.CurrentDispatcher.BeginInvoke(.. 

Các điều phối là một sự phụ thuộc bên ngoài và không phải là một phần của bài kiểm tra đơn vị của bạn - chúng ta có thể đảm nhận công việc điều phối.

Tôi sẽ sử dụng tính năng tiêm phụ thuộc (mans poor, Unity, etc). Tạo giao diện phù hợp đại diện cho điều phối viên. Tạo một triển khai thực sự kết thúc tốt đẹp cho điều phối viên thực sự. Tạo triển khai giả mạo sử dụng Action.BeginInvoke. Trong giả mạo bạn ghi lại tất cả các IAsyncResults trả lại cho các cuộc gọi đến BeginInvoke.
Sau đó, có một phương thức trợ giúp sẽ chờ tất cả các cuộc gọi hoàn thành mà bạn có thể sử dụng trong thử nghiệm của bạn để chờ hoàn thành.

Hoặc có một lớp cơ sở chế độ xem làm điều tương tự. Gọi cho người điều phối bình thường nhưng có thể được chỉ dẫn để gọi giả trong khi kiểm tra.

0

Tôi đã tìm thấy một giải pháp dễ dàng. Thay vì xử lý khung Async trong Dispatcher, tôi đã thêm một phương thức được đồng bộ hóa khác vào lớp DispatcherUtil. Gọi DoEventsSync này() - Phương pháp lợi nhuận khi tất cả các khung hình được xử lý, tôi nghĩ rằng điều này sẽ giúp ở đây:

public static class DispatcherUtil 
    { 
     [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); 
     } 

     public static void DoEventsSync() 
     { 
      var frame = new DispatcherFrame(); 
      Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, 
       new DispatcherOperationCallback(ExitFrame), frame); 
      Dispatcher.PushFrame(frame); 
     } 

     private static object ExitFrame(object frame) 
     { 
      ((DispatcherFrame)frame).Continue = false; 
      return null; 
     } 
    } 
Các vấn đề liên quan