2011-02-28 2 views
3

私は毎秒サーバーに "ハートビート信号"を送るクライアントを書いています。クライアントは、バックグラウンドスレッドでWCFサービスを呼び出して、そのアクティビティを報告します。ハートビートパターンをユニットテストするには?

ユニットテスト方法は?数秒待ってから、適切なメソッドが何回か呼び出されたかどうかを確認する必要がありますか?

シナリオテストの代わりにする必要がありますか?たぶん、クライアントのライフサイクル全体を通してサービスを継続的に呼び出すことについて心配する必要はありませんか?

WCFサービスへの1回の呼び出しをテストできますが、 "ハートビートパターン"はテストされません。

私はTDDアプローチを使用しています。 (C#、NUnit、Moq)

提案や例はありますか?

EDIT:

私はそれが十分明確ではなかったと思います。

これは私が持っているものの非常に簡単なバージョンです:

public class FeedService 
{ 
    private Timer t; 

    public FeedService() 
    { 
     t.Interval = 1000; 
     t.Elapsed += TimerElapsed; 
     t.Start(); 
    } 

    private void TimerElapsed(object sender, ElapsedEventArgs e) 
    { 
     t.Stop(); 
     SendHeartbeat(); 
     t.Start(); 
    } 
} 

...これは私のテストで:

[Test] 
public void Heartbeat_called_twice_after_2_seconds() 
{ 
    var mockFeedService = new Mock<FeedService>(); 

    Thread.Sleep(2000); 
    mockFeedService.Verify(x => x.SendHeartBeat(), Times.AtLeast(2)); 
} 

私は2つの質問があります。
1)なぜテストは常に失敗しますか?私が間違っていることは何ですか?
2)私はそれをまったくテストすべきですか?

答えて

5

テストする機能は、最初に分離されている必要があります。たとえば、この場合、テストできる2つの側面があります。 1つは、ヒアビートコンポーネントが実際に指定されたスケジュールでハートビートメッセージを送信することです。もう1つは、サービスがメッセージを受信することです。サービスを抽象化する場合は、サービスの実装とは別に、ビヘイビアーコンポーネントをテストすることができます。これは、ユニットテストで、ヒアビートコンポーネントを起動してからスリープしてから、スタブまたは模擬サービスの実装によって期待された数のメッセージが受信されたことを確認することで実行できます。サービスがメッセージを受け取ることを保証するテストはintegration testであるため、「純粋な」単体テストではありません。しかし、とにかくテストしなければならないので、これもテストケースを持つことができます。

+0

ありがとうございました。 WCFサービスがメッセージを受け取っているかどうかは気にしません。私がテストする必要があるのは、エラーを返さずに毎秒メッセージを送信するクライアントの能力です。私は模擬サービスを使ってWCFサービスへの「マニュアル」呼び出しをテストしましたが、これは私が達成しようとしているものではありません。メソッド "SendHeartbeat"はプライベートでなければならず、TimerElapsedで呼び出される必要があります。 – Novitzky

2

サービスとのやりとりを「ゲートウェイ」タイプのクラスでラップします。これはあなたのテストのモックに置き換えることができます。モックは、あなたが行った呼び出しや必要な統計をカウントすることができます。

よろしく、 モルテン

+0

明確にする。このソリューションは部分リペア(ラッピング)、パーツテスト、パーツモックですが、テストが簡単なソリューションでは、より強力なデザインになることがわかります。 – Morten

0

あなたがをテストするシナリオは、厳密に言えば、統合テストです。

私は同様の試験・建設・シナリオに撮影したアプローチは、この便利な機能を使用することです:

/// <summary> 
/// Wait no longer than @waitNoLongerThanMillis for @thatWhatWeAreWaitingFor to return true. 
/// Tests every second for the 
/// </summary> 
/// <param name="thatWhatWeAreWaitingFor">Function that when evaluated returns true if the state we are waiting for has been reached.</param> 
/// <param name="waitNoLongerThanMillis">Max time to wait in milliseconds</param> 
/// <param name="checkEveryMillis">How often to check for @thatWhatWeAreWaitingFor</param> 
/// <returns></returns> 
private bool WaitFor(Func<bool> thatWhatWeAreWaitingFor, int checkEveryMillis, int waitNoLongerThanMillis) 
{ 
    var waitedFor = 0; 
    while (waitedFor < waitNoLongerThanMillis) 
    { 
     if (thatWhatWeAreWaitingFor()) return true; 

     Console.WriteLine("Waiting another {0}ms for a situation to occur. Giving up in {1}ms ...", checkEveryMillis, (waitNoLongerThanMillis - waitedFor)); 
     Thread.Sleep(checkEveryMillis); 
     waitedFor += checkEveryMillis; 
    } 
    return false; 
} 

使用法:

// WaitFor (transaction to become failed, checkEverySoOften, waitNoLongerThan) 
int wait = (Settings.EventHandlerCoordinatorNoActivitySleepTime + 5) * 1000; 
var failedEventExists = WaitFor(() => EventQueueManager.GetFailedEvents(0, 10).TotalRecords > 0, checkEveryMillis: 1000, waitNoLongerThanMillis: wait); 

if (!failedEventExists) 
    Assert.Fail("Waited longer than " + wait + " without any evidence of the event having been handled. Expected to failed event on the queue."); 

それは.Net4ので、C#の機能のみ利用可能使用していますが、その最近のほとんどの.Net開発者に適しています。

関連する問題