2

我正在构建一个计时器类,但我无法通过测试。我想测试当计时器上的时间过去时调用一个方法。

我有以下课程:

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();   
    }
}

和测试,使用最小起订量:

[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(),它就可以工作。

难道我做错了什么?

4

3 回答 3

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.

ITimerthen 成为 的依赖项,TimeoutTimer并在构造函数中或作为属性传递给它。

在您的测试中,您可以模拟计时器,使其与您的测试同步而无需等待(例如,通过控制类手动触发事件)。

于 2012-10-05T20:24:45.710 回答
2

好吧,您在这里处理的是异步操作。如果您在处理程序中放置一个断点并通过代码进行调试,并且如果您在验证行上等待一个拼写,那么当您跨过验证行时,您将看到处理程序确实执行了。您的问题是您的测试在处理程序有机会触发之前完成。

于 2012-10-05T20:24:32.463 回答
-1

您必须在测试中引发 Elapsed 事件。

我怀疑是新的计时器引起了麻烦。您可以尝试使其可注入,然后将其注入测试并引发事件。

于 2012-10-05T20:25:38.733 回答