NUnitでeventのテストをする。その二。そして訂正。

3/30日に「NUnitでeventのテストをする。」という記事を書いたのですが、当初この方法でそれなりにうまく行っていたのですが、イベントをキックするメソッドを呼び出してからそれなりに時間のかかる処理ですと、当然イベントが呼び出される前にNUnitのGUIランナーがテストクラスを開放してしまうので、イベントメソッドが呼び出されずテストとしてはグリーンなんだけど意図した終わり方では当然無いと言うことになります。

ようは何とかしてイベントが呼び出されるまで、NUnitのGUIランナーをつなぎ止める。つまりは、Testメソッドが終わらないようにしないと行けないわけです。そういうことで、どうしたらいいんだろうと悩んでいたのですが、以下の記事で助かりました。

//指定した日付のデータをデータベースから取得する
[Test]
public void TestGetLogData() {
    //ManualResetEventのインスタンスを作るよ!
   ManualResetEvent manualEvent = new ManualResetEvent(false);
    //イベントが呼び出されたことを示すフラグを設定するよ
    bool evenFired = false;
    //必要な設定を読み込むよ
    var settings = LogClientSettings.Load(testDataPath);
    //テスト対象のインスタンスを作るよ
    var model = new LogModel(settings);
    //イベントメソッドを定義してやるよ
    model.LogGetted += (o, e) =>; {
      Console.WriteLine("Record Count {0}", model.Logs.Count);
        //イベント発生のフラグを立てるよ
        evenFired = true;
        //待機を解除するよ
        manualEvent.Set();
    };
    //Event Fire!!
    model.GetLogData(new DateTime(2010, 4, 26));
    //1秒待機するよ。
    manualEvent.WaitOne(1000, false);
    //イベント発生のフラグが立っていたらテスト成功!!
    Assert.IsTrue(evenFired, "GetLogData Fired.");
}

このようなコードになります。

ManualResetEvent をつかって、まず、イベント呼び出す要因となるメソッドを呼び出した後に、WaitOneを使ってこのスレッドをブロックします。Setが呼び出されるかもしくは、設定時間が経過するまでブロックされます。そして、イベントメソッドの中でSetを使ってスレッドのブロックを解除します。このようにすることでイベント発生までテストランナーを待たせることできます。

当然WaitOneでの待ち時間は調整が必要でしょう。

コメントを残す