2011-12-14 92 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(); 
    } 
} 

这是否帮助?