2012-02-02 68 views
7

如果我有一个测试对象使用定时器来定时执行一些操作,那么测试它的好方法是什么?是否使用Thread.Sleep测试了定时间隔的操作?

一个method是将定时器包装在一个接口中,并将其作为依赖注入。

但是,我想避免创建另一个抽象。看来我可以通过注入更新间隔而不是定时器来避免这种情况。然后在我的测试中(假设采用AAA风格的测试),我在Act之后和认定之后放了一个Thread.Sleep,使用非常小的时间值,因此测试不需要很长时间就可以运行。

这是一个坏主意吗?我知道它可能并不完全遵循TDD的原则,但是似乎必须有一条线路,让您停止在合同中注入任何东西并注入它。

+3

”必须有一条线,在那里你停止用合同注入所有东西并注入它“ - 异端,我说;) – 2012-02-02 22:53:27

+1

Windows中线程的调度不是确定性的,所以做这样的事情可能会使你的测试失败随机。 – svick 2012-02-03 01:53:10

+0

@svick我没有真的想检查任何有关线程调度。只要我的计时器成功,就会在预期的时间内+一段宽限期内发生函数调用。像这样的情况会不会受到这些问题的影响? – 2012-02-03 14:54:47

回答

5

如果您的睡眠量在测试中没有任何意义,并且您可以将我设置为1毫秒,那么在测试中简单地休眠1毫秒应该没问题。但是,如果您想要测试具有超时的复杂计时行为以及在特定时间点采取的特定操作,则可以快速抽象出时间概念并将其注入为依赖项。然后,您的测试可以在虚拟时间内运行,并且即使代码以实时通过的方式运行,也可以毫不拖延地执行。

一个简单的方法来虚拟化的时间是用这样的:

interface ITimeService { 

    DateTime Now { get; } 

    void Sleep(TimeSpan delay); 

} 

class TimeService : ITimeService { 

    public DateTime Now { get { return DateTime.UtcNow; } } 

    public void Sleep(TimeSpan delay) { Thread.Sleep(delay); } 

} 

class TimeServiceStub : ITimeService { 

    DateTime now; 

    public TimeServiceStub() { 
    this.now = DateTime.UtcNow; 
    } 

    public DateTime Now { get { return this.now; } } 

    public void Sleep(TimeSpan delay) { 
    this.now += delay; 
    } 

} 

你将不得不如果你需要像计时器射击等

2

扶养注入更具反应性的行为来扩展这个想法完全避免你的生产代码中有任何“测试”代码的方法(比如设置单元测试的时间间隔)。

但是,在这种情况下,我会使用设置的间隔代码,但在单元测试和生产中都使用它。生产将其设置为任何值,单元测试将其设置为非常小的值(10ms?)。那么在生产中你将不会有任何死代码。

如果你设置了间隔,我不明白你为什么需要Thread.Sleep?只要你的单元测试阻止,直到你从主题获得事件(或不断轮询主题)。无论你使用什么方法。 “

+0

我不太确定如何在没有'Thread.Sleep'的情况下编写代码...我之前使用过一个'AutoResetEvent'来测试事情,但我不知道如何使用模拟框架来做到这一点。任何例子?代码示例可能会帮助我更好地理解您的意思。 – 2012-02-03 14:45:48

相关问题