2012-01-25 8 views
2

TDDを使用してWPFアプリケーションを開発しています。私たちはすでにこのソリューションを2年間働いているので、大量のテストを書いています(現在、ほぼ2000件のテストが行​​われています)。非同期コードを検証するテストを最適化する方法は?

マルチスレッドと非同期の機能を実装する必要のあるクラスがいくつかあります。たとえば、メッセージを送受信したり、メッセージを解析したりすることができる通信コンポーネントです。依存関係は常にRhinoMockを使って嘲笑されます。これらのクラスをターゲットに

我々のテスト・メソッドは、以下のように、非常によく似て:あなたが見ることができるように、このテストはのThread.sleep()のために少なくとも200ミリ秒を実行します

[TestMethod] 
public void Method_Description_ExpectedResult(){ 
    // Arrange 
    var myStub = MockRepository.GenerateStub<IMyStub>(); 
    var target = new MyAsynchronousClass(myStub); 

    // Act 
    var target.Send("Foo"); 
    Thread.Sleep(200); 

    //Assert 
    myStub.AssertWasCalled(x => x.Bar("Foo")); 
} 

。 AssertWasCalledをアクティブなポーリング方法で置き換えるテストを最適化しました。このように:私たちは今、このWaitFor.True(...)メソッドを使用することができます

public static bool True(Func<bool> condition, int times, int waitTime) 
{ 
    for (var i = 0; i < times; i++) 
    { 
     if (condition()) 
      return true; 
     Thread.Sleep(waitTime); 
    } 

    return condition(); 
} 

にAssertWasCalledを変更することで:

var fooTriggered = false; 
myStub.Stub(x => x.Bar("Foo")).Do((Action)(() => fooTriggered = true))); 

WaitFor.True(() => fooTriggered, 20, 20); 
Assert.IsTrue(fooTriggered); 

この構築物は、とにかく条件が一致した場合、以前に終了しますが、 - これは私たちにとっては長すぎます。 2000テストのすべてを実行するには約5分(ビルドと実行)が必要です。

このようなコードを最適化する方法はありますか。

答えて

2

モニターを使用できます。それは無料ですまで、モニターの中に書かれたコードを実行することはできません

[TestMethod] 
public void Method_Description_ExpectedResult(){ 
    // Arrange 
    var waitingRoom = new object(); 
    var myStub = MockRepository.GenerateStub<IMyStub>(); 
    myStub.Setup(x => x.Bar("Foo")).Callback(x => 
     { 
      Monitor.Enter(waitingRoom); 
      Monitor.Pulse(waitingRoom); 
      Monitor.Exit(waitingRoom); 
     } 

    var target = new MyAsynchronousClass(myStub); 

    // Act 

    Monitor.Enter(waitingRoom); 
    target.Send("Foo"); 
    Monitor.Wait(waitingRoom); 
    Monitor.Exit(waitingRoom); 

    //Assert 
    myStub.AssertWasCalled(x => x.Bar("Foo")); 
} 

:私はそれが非常にコンパイルされていませんが、同様に、それは何かを見ていきますので、もし私に言い訳してくださいこれを作ってるんです。このテストでは、Monitor.Waitが呼び出されるまで、動作中のスレッドが待機します。次に、コールバックがモニターに入り、パルスを送ることができます。テストが "起動"し、コールバックがモニタを終了すると、コントロールが戻って終了し、Assertを実行できるようになります。

私がカバーしていない唯一のことは、Bar( "Foo")が呼び出されないとハングするので、タイマーパルスをスレッドにも持たせたいということです。

複雑な監視ビットを使用するクラスを作成することができます。 This is one I wroteは、UIオートメーションの非同期チェックを処理します。あなたがやっていることがあなたを助けるかもしれないことに適応させる。

+0

ありがとう、私はこのようなテスト方法が好きです!これを試してみる。 – Guffel

+0

ああ、見た、私はMonitor.Wait(waitingRoom、) - だから、奇妙なタイマーのgubbinsを行う必要はありません。ニース。 – Lunivore

関連する問題