如何先开发一个StopWatch类测试?
我目前正在尝试实现一个 StopWatch 类。界面类似于:
interface IStopWatch {
void Run();
void Stop();
int SecondsElapsed { get; }
int MinutesElapsed { get; }
}
基本上我的应用程序需要使用 StopWatch
,但出于测试目的,最好有一种人为修改 StopWatch
es 的方法。结果,这就是我让所有代码引用 IStopWatch
而不是 .NET 的 System.Stopwatch
的原因。
当我尝试开发这个测试优先时,我必须在编写测试后才为我的 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() 返回我想要的任何内容想。
I'm currently trying to implement a StopWatch
class. The interface is something like:
interface IStopWatch {
void Run();
void Stop();
int SecondsElapsed { get; }
int MinutesElapsed { get; }
}
Basically my app will need to use a StopWatch
, but for testing purposes it'd be nice to have a way of artifially modifing a StopWatch
es' results, so that is the reason I am making all my code reference an IStopWatch
instead of .NET's System.Stopwatch
.
As I'm trying to develop this Test-First, I'll have to make code for my StopWatch
class only after writing its tests. I already realized that the tests I'm going to do aren't going to be Unit-Tests, as I'm using .NET's System.Stopwatch
class internally.
So, in my undertanding, the only thing I can do now are tests that look like the following:
[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);
}
I know I can't just run this as often as my Unit-Tests, but I think there is nothing I can do about this. Is my approach correct or am I missing something?
Thanks
Edit
So I ended up following both Quinn351 and Sjoerd's advices and coded something that uses DateTimes instead of .NET's Stopwatch class:
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);
}
}
This allows me to make other implementations that have getter/setters for both dates so I can make GetTimeElapsed() return whatever I want.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
为什么要“人为地修改秒表的结果”?!如果您要修改结果,测试的全部目的是什么?
至于测试,您还应该测试 stop 方法,并且应该测试秒数是否大约是分钟数的 60 倍。
您正在编写的类也可以在内部使用 StopWatch,然后根据请求修改结果(然后您可以随时返回到原始结果)。
PS:方法名称应该更短并且没有下划线。
Why would "artifially modifing a StopWatches' results"?! What's the whole purpose of testing if your going to modify your results?
As for testing you should also test the stop method and you should test if the amount of seconds is roughly 60 times more than the amount of minutes.
The class you are writing could also use StopWatch internally and then modify results as requested (then you can always go back to the original results).
PS: Method names should be shorter and not have underlines.
您的秒表类可能从某个地方获取日期和时间。创建一个返回当前日期的对象。这将是一个非常简单的课程。测试时,传入一个模拟对象,它返回一个假的日期和时间。这样,您就可以在测试中假装已经过去了很多秒。
Your stopwatch class probably gets the date and time from somewhere. Make an object which returns the current date. This would be a very simple class. When testing, pass in a mock object instead, which returns a fake date and time. This way, you can pretend in your test as if many seconds have elapsed.
一个问题是秒表在具有可变时钟速度的处理器(即最新的处理器)上不准确,如以下讨论所示
C# 秒表显示不正确的时间
因此,使用 Thread.Sleep 不会为您提供准确的时间。您最好使用 DateTime.Now 实现您自己的秒表版本
One problem is that Stopwatch is not accurate on processors with variable clock speeds i.e. most current ones, as can be seen with the following discussion
C# Stopwatch shows incorrect time
So using Thread.Sleep wont give you an accurate time. You would be better to implement your own version of Stopwatch using DateTime.Now
作为上面编辑的旁白:不要使用此方法来确定经过的时间!它在以下情况下无法正常工作:
...并且可能还有许多其他条件。
As an aside to the EDIT above: Do not use this method to determine elapsed time! It does not work well when:
... and probably a number of other conditions.