【发布时间】:2013-06-05 09:46:17
【问题描述】:
我目前正在抽象计时器的概念,以便我的类可以在测试中使用模拟计时器或在操作模式下使用不同的实现(例如线程池计时器、线程仿射计时器等)。因此,我创建了这个界面:
public interface ITimer : IDisposable
{
bool IsEnabled { get; }
bool IsAutoResetting { get; set; }
TimeSpan Interval { get; set; }
void Start();
void Stop();
event EventHandler IntervalElapsed;
}
现在我想创建一个适应System.Threading.Timer 类并实现该接口的包装器。我想使用测试驱动开发来做到这一点。我的班级目前看起来有点像这样:
public sealed class ThreadPoolTimer : ITimer
{
private readonly Timer _timer;
public bool IsEnabled { get; private set; }
public bool IsAutoResetting { get; set; }
public TimeSpan Interval { get; set; }
public ThreadPoolTimer()
{
Interval = this.GetDefaultInterval();
_timer = new Timer(OnTimerCallback);
}
public void Dispose()
{
_timer.Dispose();
}
public void Start()
{
}
public void Stop()
{
}
private void OnTimerCallback(object state)
{
OnIntervalElapsed();
}
public event EventHandler IntervalElapsed;
private void OnIntervalElapsed()
{
var handler = IntervalElapsed;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
我的实际问题是:您将如何编写描述Start、Stop 和IntervalElapsed 行为的(软实时)要求的单元测试?
在我看来,我应该使用例如AutoResetEvent 并检查事件是否在特定时间跨度内引发(可能是 +/- 3 毫秒)。但我认为编写该代码有点违反 DAMP(描述性和有意义的短语)原则。有没有更简单的方法来做到这一点?
我是否应该将 System.Threading.Timer 的依赖项设为外部,然后可能使用 shim 进行测试?不幸的是,.NET 计时器没有通用接口(这会使我的工作过时......)
你对这个话题有什么看法?是否有任何我尚未找到但我应该阅读的文档?
很抱歉在这篇文章中实际上有多个问题,但我认为这种软实时需求测试非常有趣。
【问题讨论】:
-
我不认为这是重复的,因为所有这些问题都涉及封装计时器的类以及如何模拟它,但没有一个使用 TDD 实现实际接口。关于此的其他问题是例如stackoverflow.com/questions/879971/… 或 stackoverflow.com/questions/12045/…
-
创建一个包装器感觉就像是一种气味。我认为框架中的计时器类可以保证工作。我会创建子类来测试主题以调用我的计时器处理程序或注入我自己的时间间隔来编写一些集成测试。
-
@bryanbcook 你是如何从中抽象出来的?正如我之前提到的,.NET 中的计时器都没有实现公共接口。不创建适配器(实际上是这个包装器)意味着您不能在需要计时器的类的单元测试中从中抽象出来。
-
我的观点是,除非有一个非常有力和令人信服的抽象理由,否则可能不需要它。例如,如果没有 UI,UI 调度程序不会抽出后台任务,这可能是测试的问题。另一方面,定时器是相当有保证的,所以除非你动态地操作定时器或者需要用不同的计时策略将它换掉,否则我会质疑我为什么需要抽象。
标签: c# .net unit-testing tdd real-time