0

私は現在、StopWatchクラスを実装しようとしています。インターフェイスは次のようなものです。

interface IStopWatch {
    void Run();
    void Stop();
    int SecondsElapsed { get; }
    int MinutesElapsed { get; }
}

基本的に、私のアプリは を使用する必要がありますStopWatchが、テストの目的で、StopWatches の結果を人為的に変更する方法があると便利です。そのため、すべてのコード参照IStopWatchを .NET の ではなく にしていますSystem.Stopwatch

この Test-First を開発しようとしているので、StopWatchクラスのテストを作成した後にのみ、クラスのコードを作成する必要があります。System.Stopwatch.NET のクラスを内部で使用しているため、これから行うテストは単体テストではないことは既に認識しています。

したがって、私の理解では、今できることは次のようなテストだけです。

[TestMethod]
public void Right_After_Calling_Run_Elapsed_Minutes_Equals_Zero() {
    IStopWatch stopWatch = new StopWatch();
    stopWatch.Run();
    Assert.AreEqual<int>(0, stopWatch.ElapsedMinutes);
}

[TestMethod]
public void One_Second_After_Run_Elapsed_Seconds_Equals_One() {
    IStopWatch stopWatch = new StopWatch();
    stopWatch.Run();
    Thread.Sleep(1000 + 10);
    Assert.AreEqual<int>(1, stopWatch.ElapsedSeconds);
}

[TestMethod]
public void Sixty_Seconds_After_Run_Elapsed_Minutes_Equals_One() {
    IStopWatch stopWatch = new StopWatch();
    stopWatch.Run();
    Thread.Sleep(60 * 1000 + 1000);
    Assert.AreEqual<int>(1, stopWatch.ElapsedMinutes);            
}

これを単体テストと同じくらい頻繁に実行できないことはわかっていますが、これについてできることは何もないと思います。私のアプローチは正しいですか、何か不足していますか?

ありがとう

編集

そこで、Quinn351 と Sjoerd の両方のアドバイスに従い、.NET の Stopwatch クラスの代わりに DateTimes を使用するコードを作成しました。

public class MyStopWatch : IMyStopWatch {
    private DateTime? firstDateTime = null;
    private DateTime? secondDateTime = null;
    private bool isRunning = false;

    public void Start() {
        isRunning = true;
        firstDateTime = DateTime.Now;
    }

    public void Stop() {
        isRunning = false;
        secondDateTime = DateTime.Now;
    }

    public void Reset() {
        firstDateTime = null;
        secondDateTime = null;
        isRunning = false;
    }

    public TimeSpan GetTimeElapsed() {
        return secondDateTime.Value.Subtract(firstDateTime.Value);
    }
}

これにより、両方の日付に対して getter/setter を持つ他の実装を作成できるため、GetTimeElapsed() が必要なものを返すようにすることができます。

4

4 に答える 4

3

なぜ「ストップウォッチの結果を人為的に変更する」のでしょうか?! 結果を変更する場合、テストの全体的な目的は何ですか?

テストに関しては、stop メソッドもテストする必要があり、秒数が分数の約 60 倍であるかどうかをテストする必要があります。

作成中のクラスは、StopWatch を内部的に使用して、要求に応じて結果を変更することもできます (その後、いつでも元の結果に戻ることができます)。

PS: メソッド名は短くし、下線を付けないでください。

于 2010-08-22T10:38:01.700 に答える
2

ストップウォッチ クラスは、おそらくどこかから日付と時刻を取得します。現在の日付を返すオブジェクトを作成します。これは非常に単純なクラスになります。テストするときは、代わりに偽の日付と時刻を返すモックオブジェクトを渡します。このようにして、テストで何秒も経過したかのように振る舞うことができます。

class DateTime {
    public Date getDate() {
        return System.DateTime.Now();
    }
}

class MockDateTime {
    public Date getDate() {
        return this.fakeDate;
    }
}

class StopwatchTest {
    public void GoneInSixtySeconds() {
        MockDateTime d = new MockDateTime();
        d.fakeDate = '2010-01-01 12:00:00';
        Stopwatch s = new Stopwatch();
        s.Run();
        d.fakeDate = '2010-01-01 12:01:00';
        s.Stop();
        assertEquals(60, s.ElapsedSeconds);
    }
}
于 2010-08-22T10:32:05.283 に答える
1

問題の 1 つは、次の説明でわかるように、クロック速度が可変のプロセッサ、つまり最新のプロセッサではストップウォッチが正確ではないことです。

C# ストップウォッチが間違った時間を表示する

したがって、 Thread.Sleep を使用しても正確な時間が得られません。DateTime.Now を使用して独自のバージョンのストップウォッチを実装することをお勧めします。

于 2010-08-22T10:37:23.013 に答える