2011-12-14 42 views
7

Chúng tôi có một thành phần COM do nhà sản xuất được viết bằng C++. Bây giờ chúng ta muốn kiểm tra các chức năng và sự kiện của nó trong một dự án thử nghiệm C#. Các bài kiểm tra hàm khá đơn giản. Tuy nhiên, các sự kiện không bao giờ được kích hoạt.Kiểm tra đơn vị sự kiện COM?

MyLib.MyClass m = new MyLib.MyClass(); 
Assert.IsTrue(m.doStuff()); // Works 

// This does not work. OnMyEvent is never called! 
m.MyEvent += new MyLib.IMyClassEvents_MyEventHandler(OnMyEvent); 
m.triggerEvent(); 

Tôi đã googled điều này và đọc về các sự cố tương tự tại đây trên StackOverflow. Tôi đã thử tất cả các phương pháp được đề xuất nhưng không thể làm cho nó hoạt động!

Cho đến nay tôi đã thử chạy thử nghiệm của mình với số active dispatcher nhưng không thành công. Tôi cũng đã cố gắng tự bơm các thông điệp trong chủ đề chính bằng cách sử dụng Dispatcher.PushFrame(). Không có gì. Sự kiện của tôi không bao giờ kích hoạt. Tôi đã tạo một dự án WinForms đơn giản và xác minh rằng các sự kiện của tôi hoạt động trong một thiết lập bình thường. Do đó, vấn đề này chỉ áp dụng cho các bài kiểm tra đơn vị.

Hỏi: Làm cách nào để thực hiện Kiểm tra đơn vị C# thông thường có thể kích hoạt thành công trình xử lý sự kiện hoạt động?

Có ai đó ở đó phải có mẫu đang hoạt động! Hãy giúp tôi.

+0

Vâng, kiểm tra đơn vị không thành công. Các máy chủ COM có xu hướng cần chương trình để bơm vòng lặp tin nhắn trước khi chúng có thể tạo ra các sự kiện. Nó là một phần của hợp đồng STA. Liên hệ với tác giả thành phần để được hỗ trợ. –

+0

Máy chủ COM là thành phần riêng của chúng tôi - mà chúng tôi muốn kiểm tra. Việc bơm tin nhắn, như bạn nói, là điều cần thiết. Vì vậy, câu hỏi vẫn còn; làm thế nào để bạn thực hiện điều này trong một bài kiểm tra đơn vị? – l33t

+0

@NOPslider Bạn đang sử dụng khung kiểm thử đơn vị nào? Các phiên bản sau của NUnit mặc định cho một mô hình luồng MTA. – vcsjones

Trả lời

1

Nếu đối tượng COM của bạn là một đối tượng STA, bạn có thể cần phải chạy một vòng lặp tin nhắn để làm cho các sự kiện của nó cháy.

Bạn có thể sử dụng gói nhỏ xung quanh đối tượng ApplicationForm để thực hiện điều đó. Đây là một ví dụ nhỏ tôi đã viết trong một vài phút.

Lưu ý rằng tôi đã không chạy hoặc kiểm tra nó, vì vậy nó có thể không hoạt động, và dọn dẹp có lẽ nên tốt hơn. Nhưng nó có thể cung cấp cho bạn một hướng cho một giải pháp.

Sử dụng phương pháp này, các lớp thử nghiệm sẽ giống như thế này:

[TestMethod] 
public void Test() 
{ 
    MessageLoopTestRunner.Run(

     // the logic of the test that should run on top of a message loop 
     runner => 
     { 
      var myObject = new ComObject(); 

      myObject.MyEvent += (source, args) => 
      { 
       Assert.AreEqual(5, args.Value); 

       // tell the runner we don't need the message loop anymore 
       runner.Finish(); 
      }; 

      myObject.TriggerEvent(5); 
     }, 

     // timeout to terminate message loop if test doesn't finish 
     TimeSpan.FromSeconds(3)); 
} 

Và mã cho MessageLoopTestRunner sẽ là một cái gì đó như thế:

public interface IMessageLoopTestRunner 
{ 
    void Finish(); 
} 

public class MessageLoopTestRunner : Form, IMessageLoopTestRunner 
{ 
    public static void Run(Action<IMessageLoopTestRunner> test, TimeSpan timeout) 
    { 
     Application.Run(new MessageLoopTestRunner(test, timeout)); 
    } 

    private readonly Action<IMessageLoopTestRunner> test; 
    private readonly Timer timeoutTimer; 

    private MessageLoopTestRunner(Action<IMessageLoopTestRunner> test, TimeSpan timeout) 
    { 
     this.test = test; 
     this.timeoutTimer = new Timer 
     { 
      Interval = (int)timeout.TotalMilliseconds, 
      Enabled = true 
     }; 

     this.timeoutTimer.Tick += delegate { this.Timeout(); }; 
    } 

    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 

     // queue execution of the test on the message queue 
     this.BeginInvoke(new MethodInvoker(() => this.test(this))); 
    } 

    private void Timeout() 
    { 
     this.Finish(); 
     throw new Exception("Test timed out."); 
    } 

    public void Finish() 
    { 
     this.timeoutTimer.Dispose(); 
     this.Close(); 
    } 
} 

Điều đó giúp đỡ?