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

私はこれを見つけて、StackOverflowで同様の問題について読んでいます。私はすべての提案された方法を試しましたが、それを動作させることはできません!

これまでのところ、active dispatcherでテストを実行しようとしましたが、成功しませんでした。私はまた、Dispatcher.PushFrame()を使って手動でメインスレッドにメッセージをポンピングしようとしました。何もない。私の出来事は決して誘発しない。私は単純なWinFormsプロジェクトを作成し、私のイベントは通常の設定で動作することを確認しました。したがって、この問題は単体テストにのみ適用されます。

Q:アクティブなイベントハンドラを正常に起動できる通常のC#ユニットテストを作成するにはどうすればよいですか?

誰かがそこに働いているサンプルを持っているはずです!助けてください。

+0

ユニットテストに失敗しました。 COMサーバーは、プログラムがイベントを生成する前にメッセージループをポンピングする必要がある傾向があります。それはSTA契約の一部です。サポートについては、コンポーネント作成者にお問い合わせください。 –

+0

COMサーバーは私たち独自のコンポーネントであり、テストする必要があります。メッセージをポンピングすることは、あなたが言うように、不可欠です。だから問題は残る。あなたは単体テストでこれをどのように達成しますか? – l33t

+0

@NOPsliderどのようなユニットテストフレームワークを使用していますか? NUnitのそれ以降のバージョンでは、デフォルトでMTAスレッドモデルが使用されます。 – vcsjones

答えて

1

COMオブジェクトがSTAオブジェクトの場合は、イベントを発生させるためにメッセージループを実行する必要があります。

ApplicationFormオブジェクトの周りに小さなラッピングを使用してそのことを行うことができます。ここに私が数分で書いた小さな例があります。

私は実行していないかテストしているため、動作しない可能性があります。クリーンアップがおそらくより良いはずです。しかし、それはあなたに解決策の方向性を与えるかもしれません。

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

がその助けを行います。そのようなものになるだろう

[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のコード:このアプローチを使用

、テストクラスは次のようになりますか?

関連する問題