如何首先开发StopWatch类测试?

时间:2010-08-22 09:41:23

标签: c# unit-testing testing tdd test-first

我目前正在尝试实施StopWatch课程。界面类似于:

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

基本上我的应用程序需要使用StopWatch,但出于测试目的,有一种人工修改StopWatch es'结果的方式很好,所以这就是我的原因使我的所有代码都引用IStopWatch而不是.NET的System.Stopwatch

当我正在尝试开发这个Test-First时,我必须在编写测试后才为我的StopWatch类创建代码。我已经意识到我要做的测试不会是单元测试,因为我在内部使用.NET的System.Stopwatch类。

所以,在我的承诺中,我现在唯一能做的就是测试如下:

[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 个答案:

答案 0 :(得分:3)

为什么“人为地修改StopWatches”结果“?!如果您要修改结果,测试的全部目的是什么?

至于测试,你还应该测试停止方法,你应该测试秒数是否大约是分钟数的60倍。

您正在编写的类也可以在内部使用StopWatch,然后根据请求修改结果(然后您可以始终返回到原始结果)。

PS:方法名称应该更短,没有下划线。

答案 1 :(得分: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);
    }
}

答案 2 :(得分:1)

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

C# Stopwatch shows incorrect time

因此使用Thread.Sleep不会给你准确的时间。您最好使用DateTime.Now

实现自己的秒表版本

答案 3 :(得分:0)

除了上面的编辑之外:不要使用这种方法来确定经过的时间!它在以下情况下效果不佳:

  • 列表项
  • 正在设置时钟或时区
  • 夏令时开始或结束
  • 时钟不可靠(例如在VM内)

......可能还有很多其他条件。