单元测试系统.timers.timer

del*_*ree 13 .net c# unit-testing

我一直在阅读有关定时器和线程的单元测试的问题.我找到了关于单元测试system.threading.timers的SO问题,但是我需要对system.timers.timer和一个包装类进行单元测试,这对于这个问题似乎并不顺利.

我只需要知道如何模拟计时器和/或系统时间,以便对它进行单元测试.我似乎无法在谷歌的任何地方找到这个.

编辑和更新:有意义的是,如果我通过如下包装来提取计时器,我可以生成一个计时器并使用模拟将其替换为不同的计时器.然后,相关部分将采用我在运行时注入的计时器(原始而不是模拟)并测试它的已用事件代码.

k.m*_*k.m 23

什么阻止你包装这个?

public interface ITimer
{
    void Start(double interval);
    void Stop();
    event ElapsedEventHandler Elapsed;
}
Run Code Online (Sandbox Code Playgroud)

这几乎是你所有的界面需求.让我们看看它是如何发展的(注意你当然可以暴露更多的Timer属性,但这是非常基本的东西应该足够了):

public class MyTimer : ITimer
{
    private Timer timer = new Timer();

    public void Start(double interval)
    {
        timer.Interval = interval; 
        timer.Start();
    }

    public void Stop()
    {
        timer.Stop();
    }

    public event ElapsedEventHandler Elapsed
    {
        add { this.timer.Elapsed += value; }
        remove { this.timer.Elapsed -= value; }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您将如何在测试中使用它(假设我们使用FakeItEasy作为选择的模拟框架):

var timerFake = A.Fake<ITimer>();
var classUnderTest = new MyClass(timerFake);

// tell fake object to raise event now
timerFake.Elapsed += Raise.With<ElapsedEventArgs>(ElapsedEventArgs.Empty).Now;

// assert whatever was supposed to happen as event response, indeed did
Assert.That(classUnderTest.ReceivedEvent, Is.True);
Run Code Online (Sandbox Code Playgroud)

上面的例子实际上确实测试发生在代码一旦计时器上的事件被引发.考虑MyClass看起来像这样:

public class MyClass
{
    private ITimer timer;

    public MyClass(ITimer timer)
    {
        this.timer = timer;
        this.timer.Elapsed += TimerElapsedHandler;
    }

    public bool ReceivedEvent { get; set; }

    private void TimerElapsedHandler(object sender, ElapsedEventArgs e)
    { 
        ReceivedEvent = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

在测试中,我们强制计时器在需要时加注,我们TimerElapsedHandler通过断言ReceivedEvent属性来检查执行中的代码是否已设置.实际上,这种方法可能会做得更多,但这只会改变我们做断言的方式 - 想法保持不变.


编辑:你也可以尝试Moles,这个框架允许你生成任何框架类型/方法的假货.但是,如果你想要的是模拟计时器,我会选择包装器.