3

私はC#(.NET 4.5)でユニットテストクラスを書いています。テストの1つでは、クラスのインスタンスFeedbackDaoが作成された後、さまざまなプロパティの値をチェックしています。構築時に、のFeedbackDateプロパティFeedbackDaoはに設定されDateTime.Nowます。

FeedbackDao feedbackDao = new FeedbackDao();
// a couple of lines go here then I set up  this test:
Assert.IsTrue(feedbackDao.FeedbackDate.CompareTo(DateTime.Now) < 0);

DateTime.Now私の仮定では、feedbackDao.FeedbackDateは、ミリ秒だけであっても、返される現在の時刻よりも常に少し早く、IsTrueテストは常に合格するはずですが、合格することもあれば、失敗することもあります。このようなメッセージを追加すると:

Assert.IsTrue(feedbackDao.FeedbackDate.CompareTo(DateTime.Now) < 0,
                feedbackDao.FeedbackDate.CompareTo(DateTime.Now).ToString());

メッセージは、-1(FeedbackDateより前を意味するNow)を読み取る場合と、0(DateTimeインスタンスが等しいことを意味する)を読み取る場合があります。

なぜ いつもより早くないのFeedbackDateですか?そして、その比較を信頼できない場合、いつ構築されるかの値をチェックするための厳密なテストをどのように書くことができますか?NowFeedbackDateFeedbackDao

4

7 に答える 7

8

私の仮定では、feedbackDao.FeebackDateは、たとえミリ秒だけであっても、DateTime.Nowによって返される現在の時刻よりも常に少し早くする必要があります。

何があなたをそう思わせたのですか?これは、1000回の呼び出しに少なくとも1秒かかることを示唆していますが、これはありそうもないことです。

それに加えて、DateTime.NowIIRCの実用的な粒度は約10〜15ミリ秒であり、2回続けて呼び出すと、同じ値が2回得られることがよくあります。DateTime.Now

IClockテスト容易性(および依存関係の明確な表現)の目的で、現在のシステム時刻を抽出するために常に使用される「クロック」インターフェース()を使用するのが好きです。次に、適切と思われる方法で時間を制御するための偽の実装を作成できます。

さらに、このアサーションには欠陥があります。

Assert.IsTrue(feedbackDao.FeebackDate.CompareTo(DateTime.Now) < 0,
                feedbackDao.FeebackDate.CompareTo(DateTime.Now).ToString());

DateTime.Now2回評価されるため、欠陥があります。そのため、レポートされる値は、チェックする値と必ずしも同じではありません。それは次のように良いでしょう:

DateTime now = DateTime.Now;
Assert.IsTrue(feedbackDao.FeebackDate.CompareTo(now) < 0,
                feedbackDao.FeebackDate.CompareTo(now).ToString());

またはさらに良い:

DateTime now = DateTime.Now;
DateTime feedbackDate = feedbackDao.FeebackDate;
Assert.IsTrue(now < feedbackDate,
              feedbackDate + " should be earlier than " + now);
于 2012-08-09T11:51:30.087 に答える
1

私は通常、モックデータを使用してロジックを検証します。私はモックデータを中心にテストシナリオを進化させています。DBMによって提案されたように。モックデータは、一般的に静的または構成可能な既知のデータのセットです。一般的な方法は、すべてのテストデータを含むXMLファイルを用意し、必要に応じてそれらをロードすることです。私たちのプロジェクトで例をあげることができます。

于 2012-08-10T08:01:51.163 に答える
1

ユニットテストを行うとき、私DateTime.Nowは外部依存関係であると考えているため、何かをモックする必要があります。を含むシナリオをテストするときに過去に行ったことは、クラスのコンストラクターを介してDateTime.Now渡されたところです。これにより、テスト中にモックを作成できます。Func<DateTime>DateTime.Now

前回これを行ったとき、単一のプロパティをラップする新しいインターフェイスとクラスを作成するのはばかげていると感じたので、プロパティIClockをラップするためにインターフェイスのようなものを使用するというJonSkeetの提案よりもこれを好みます。DateTime複数の静的プロパティをテストする必要がある場合は、私はその提案DateTimeに間違いなく同意します。IClock

例えば、

public class Foo
{
    private readonly Func<DateTime> timeStampProvider;
    public Foo(Func<DateTime> timeStampProvider)
    {
        this.timeStampProvider = timeStampProvider;
    }

    public Foo() : this(() => DateTime.Now)
    {
    }

    public bool CompareDate(DateTime comparisonDate)
    {
        // Get my timestamp
        return comparisonDate > timeStampProvider();
    }
}

次に、テスト中に、

var testFoo = new Foo(() => new DateTime(1, 1, 2010));
于 2012-08-09T12:37:18.553 に答える
1

あなたのテストはそれがそうであるほど有用ではありません、あなたは値がより小さいと主張していますが、DateTime.Nowそれはそれが期待値に正しく設定されたことを意味しません。日時が初期化されていない場合は、がありDateTime.MinValue、その値は常にテストに合格します

このテストはテストと同じくらい有効でfeedbackDao.FeebackDate.CompareTo(DateTime.Now) <= 0あり、この質問を書く動機となった問題は発生しません。

モックへの依存関係を抽出するDateTime.Nowか、モックをサポートするモックフレームワークを使用しDateTime.Nowて、値が正しい値に初期化されていることを表明する必要があります。Microsoft Molesを確認できます。これは、VS 2012でFakesに名前が変更されました。これは、無料であることがわかっている唯一のモックフレームワークです(VSに付属しており、で利用できるかどうかわからないため、最新バージョンのようなものです。 Express Editions)を使用すると、への呼び出しを置き換えることができますDateTime.Now

アップデート:

モックフレームワークに頼ることなく、次のようなことを行うことでテストを改善できます。

var lowerBoundary = DateTime.Now;
var dao = new FeedbackDao();
var upperBoundary = DateTime.Now;

Assert.IsTrue(dao.Date >= lowerBoundary && dao.Date <= upperBoundary);
于 2012-08-09T11:52:36.577 に答える
0

試す

Assert.IsTrue(feedbackDao.FeebackDate.CompareTo(DateTime.Now) < 1);

または

Assert.IsTrue(feedbackDao.FeebackDate - DateTime.Now < someMarginOfError);

時間は一般的にかなり細かく、多くの場合数十ミリ秒のIIRCです。

于 2012-08-09T11:51:36.060 に答える
0

システムによっては、DateTime.Nowミリ秒またはティックごとに更新されるのではなく、定期的にのみ更新されます。通常は10ミリ秒程度です。ここを参照してください:DateTime.Nowはどのくらいの頻度で更新されますか?または、現在の時刻を取得するためのより正確なAPIはありますか?

于 2012-08-09T11:52:00.493 に答える
0

DateTime.Nowは100%正確ではありません。それは約130ミリ秒増加します(ダニごとの個人的な経験から)。したがって、メソッドが十分に高速である場合、日付はdatetime.nowと等しくなり、それより小さくならない可能性が非常に高くなります。
100%正確なタイマーが必要な場合は、StopWatchクラスを使用する必要があります。
ストップウォッチへのMSDNリンク

于 2012-08-09T11:53:19.207 に答える