2011-12-14 118 views
7

我們有一個用C++編寫的自制COM組件。我們現在要在C#測試項目中測試它的函數和事件。功能測試非常簡單。但是,這些事件從未被觸發。單元測試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(); 

我已經google了這個,並在StackOverflow上閱讀了類似的問題。我嘗試了所有建議的方法,但無法使其工作!

到目前爲止,我試過用active dispatcher運行我的測試,但沒有成功。我也嘗試使用Dispatcher.PushFrame()在主線程中手動泵送消息。沒有。我的事件從未觸發。我創建了一個簡單的WinForms項目,並驗證了我的事件在正常設置下工作。因此,這個問題只適用於單元測試。

問:如何進行常規的C#單元測試,以成功觸發活動事件處理程序?

有人在那裏應該有一個工作樣本!請幫忙。

+0

那麼,單元測試失敗。 COM服務器往往需要程序在生成事件之前抽取消息循環。它是STA合同的一部分。聯繫組件作者尋求支持。 – 2011-12-14 13:53:12

回答

1

如果您的COM對象是一個STA對象,您可能需要運行一個消息循環以使其事件觸發。

您可以使用圍繞ApplicationForm對象的小包裝來做到這一點。這是幾分鐘內我寫的一個小例子。

請注意,我沒有運行或測試它,所以它可能無法正常工作,清理應該會更好。但它可能會給你一個解決方案的方向。

使用這種方法,測試類會是這個樣子:

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

而對於MessageLoopTestRunner代碼將是類似的東西:

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

這是否幫助?