我正在构建一个计时器类,但我无法进行测试通过。我想测试在计时器上的时间过去时调用方法。
我有以下课程:
public class TimeOutTimer
{
private readonly ISubscriber _subscriber;
private Timer _timer;
public TimeOutTimer(ISubscriber subscriber)
{
_subscriber = subscriber;
}
public void Start()
{
_timer = new Timer(1000);
_timer.Start();
_timer.Elapsed += TimerOnElapsed;
}
private void TimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
{
_subscriber.TimeReached();
}
}
测试,使用Moq:
[Test]
public void Start_WithValidParameters_TriggersTimeReached()
{
var subscriberMock = new Mock<ISubscriber>();
var timer = new TimeOutTimer(subscriberMock.Object);
timer.Start();
subscriberMock.Verify(subscriber => subscriber.TimeReached());
}
如果我取出Timer并直接调用_subscriber.TimeReached(),它就可以工作。
我做错了吗?
答案 0 :(得分:4)
在您的示例中,事件应在1000毫秒后调用,而您立即验证。显然,此时无法调用该事件。
简单的方法是让线程在你的测试中休眠。
[Test]
public void Start_WithValidParameters_TriggersTimeReached()
{
var subscriberMock = new Mock<ISubscriber>();
var timer = new TimeOutTimer(subscriberMock.Object);
timer.Start();
Thread.Sleep(1000);
subscriberMock.Verify(subscriber => subscriber.TimeReached());
}
然而,这并不是为基于时间的类生成单元测试的正确方法。
正确的方法是创建一个ITimer
接口,然后由基于Timer
的适配器实现。
然后ITimer
成为TimeoutTimer
的依赖项,并在构造函数中或作为属性传递给它。
在测试中,您可以模拟计时器,使其与测试同步而无需等待(例如,通过控制班级手动触发事件)。
答案 1 :(得分:2)
嗯,你正在处理异步操作。如果你在处理程序中放置一个断点并通过代码进行调试,并且如果你在验证行上等待一个咒语,那么当你跨过验证行时,你会看到处理程序确实执行了。你的问题是你的测试在处理程序有机会开始之前完成。
答案 2 :(得分:-1)
您必须在测试中提高Elapsed事件。
我怀疑这是导致麻烦的新计时器。您可以尝试将其注射,然后将其注入测试并提升事件。