0

我目前正在尝试实现一个StopWatch类。界面类似于:

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

基本上我的应用程序需要使用 a StopWatch,但出于测试目的,最好有一种人工修改StopWatches 的结果的方法,所以这就是我让所有代码引用 anIStopWatch而不是 .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 的建议,并编写了一些使用 DateTimes 而不是 .NET 的 Stopwatch 类的代码:

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

一个问题是秒表在具有可变时钟速度的处理器(即大多数当前的处理器)上不准确,如以下讨论所示

C#秒表显示不正确的时间

所以使用 Thread.Sleep 不会给你一个准确的时间。您最好使用 DateTime.Now 实现您自己的 Stopwatch 版本

于 2010-08-22T10:37:23.013 回答
0

作为上述编辑的旁白:不要使用这种方法来确定经过的时间!在以下情况下它不能很好地工作:

  • 项目清单
  • 正在设置时钟或时区
  • 夏令时开始或结束
  • 时钟在其他方面不可靠(例如在 VM 内部)

...可能还有其他一些条件。

于 2017-02-28T22:22:42.357 回答