2012-02-02 5 views
7

タイマーを使ってテスト対象のテストをしているときに、一定の時間間隔で何らかのアクションを実行すると、それをテストする良い方法はありますか?ユニットテストのTimed-intervalアクションがThread.Sleepと悪いですか?

1つのmethodは、タイマーをインターフェイスにラップし、それを依存関係として注入することです。

しかし、もう1つの抽象化を避けたいと思います。それは、タイマーではなく更新間隔を注入することで回避できるようです。私のテスト(AAAスタイルのテストを前提とする)で、の後にThread.Sleepを入力します。アサートの間で、テストに時間がかかりません。

これは悪い考えですか?おそらくTDDの原則に完全に従っているわけではないことは分かっていますが、契約をしてすべてを取り巻くことを止めて注入する行がなければならないようです。

+3

"契約書と注射ですべてを取り囲む行がある必要があります" - Heresy、私の意見;) –

+1

Windowsのスレッドのスケジューリングは確定的ではないので、このようなことをするとテストが失敗する可能性があります無作為に。 – svick

+0

@svick私は実際にスレッドのスケジューリングについては何もチェックしようとしていません。ちょうど私のタイマーは正常に機能コールが予定された期間+わずかな猶予期間内に発生するようにします。そのような状況は、まだそのような問題に脆弱ではないでしょうか? –

答えて

5

あなたが眠っている量がテストに何の意味もなく、iを1ミリ秒に設定することができれば、テストでは1ミリ秒間スリープするだけでいいはずです。

ただし、タイムアウトと特定の時点で特定のアクションが実行されている複雑なタイミング動作をテストする場合は、時間の概念を抽象化して従属として注入する方がすぐに簡単になります。その後、実時間が経過しているかのようにコードが動作しても、テストは仮想時間で動作し、遅滞なく実行できます。

時間を仮想化する簡単な方法は、このようなものを使用することです:

interface ITimeService { 

    DateTime Now { get; } 

    void Sleep(TimeSpan delay); 

} 

class TimeService : ITimeService { 

    public DateTime Now { get { return DateTime.UtcNow; } } 

    public void Sleep(TimeSpan delay) { Thread.Sleep(delay); } 

} 

class TimeServiceStub : ITimeService { 

    DateTime now; 

    public TimeServiceStub() { 
    this.now = DateTime.UtcNow; 
    } 

    public DateTime Now { get { return this.now; } } 

    public void Sleep(TimeSpan delay) { 
    this.now += delay; 
    } 

} 

はあなたが

2

依存性の注入があるなど、発射タイマーのようなより反応性の高い動作が必要な場合は、この考え方を拡張する必要があります(例えば単体テストの間隔を設定するなど)、生産コード内に「テスト」コードがあることを完全に避けるための方法です。

しかし、この場合は、設定されたインターバルコードを使用しますが、単体テストとプロダクションの両方で使用します。何かに生産を設定して、単体テストではそれを非常に少量(10ミリ秒)に設定しました。そうすれば、生産中にデッドコードがぶら下がることはありません。

間隔を設定すると、Thread.Sleepが必要な理由がわかりません。被験者からイベントを得る(または被験者に継続的に投票する)まで、単体テストをブロックしてください。どんな方法を使っていても。

+0

私は 'Thread.Sleep'なしでどのようにコード化すればよいか分かりません...私は物事をテストする前に' AutoResetEvent'を使用しましたが、私はどのように私がモックフレームワークでそれをするのか分かりません。どんな例?コードサンプルは、あなたが意味することをよりよく理解するのに役立ちます。 –

関連する問題