2012-01-31 41 views
13

我一直在阅读有关使用定时器和线程进行单元测试的问题。我发现了关于单元测试system.threading.timers的SO问题,但我需要单元测试一个system.timers.timer,并且一个包装类似乎并没有像这样顺利运行。unit testing system.timers.timer

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

编辑&更新: 它是有道理的,如果我提取定时器包装它如下,我可以生成一个计时器,并使用嘲笑取代它与一个不同的计时器。然后相关部分将在运行时注入计时器(原始的,不是模拟的)并测试已过时的事件代码。

+1

很难提出建议,因为你没有提供任何关于你想要覆盖哪个测试用例和哪个代码块代表测试用例下的逻辑的任何信息。 – sll 2012-01-31 23:09:47

+3

您需要测试计时器或测试每个事件中执行的代码吗?如果是这样,你可以把这个逻辑放到另一个类中去测试。你可以相信定时器调用它。 – ivowiblo 2012-01-31 23:22:55

+0

@ivowiblo:我不知道如何将您的评论标记为答案,但我认为这与我能找到的问题的实际答案最接近。 – deltree 2012-01-31 23:35:38

回答

22

什么阻止你包装这一个?

public interface ITimer 
{ 
    void Start(double interval); 
    void Stop(); 
    event ElapsedEventHandler Elapsed; 
} 

这几乎是所有的界面需求。让我们来看看这是怎么走(注意,您当然可以公开更多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; } 
    } 
} 

现在,你怎么会在测试中使用这个(假设我们“重新使用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); 

实施例实际上以上确实测试一旦计时器上的事件引发这种情况发生的代码。考虑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; 
    } 
} 

在测试中,我们计时器,以提高当我们需要它,我们检查是否执行在TimerElapsedHandler代码,断言ReceivedEvent属性设置。实际上,这种方法可能做的不仅仅是这些,而只会改变我们做断言的方式 - 观念依然如此。


编辑:您也可以尝试Moles,一个框架,让你产生假货任何框架类型/方法。但是,如果嘲笑定时器是你想要的,我会采用包装方法。

+0

如果我用这种方式包装它,我如何控制逝去的事件和/或模拟对象? – deltree 2012-01-31 23:20:57

+0

@deltree:你的意思是什么*如何控制事件*?如果你用这种方式包装它,你可以像其他任何接口一样嘲笑它。我会添加一个简单的例子。 – 2012-01-31 23:23:01

+0

谢谢你。这更接近我实际说的,显然不是我想说的。这是单元测试计时器被调用的好方法,但不是在经过时运行的代码。 – deltree 2012-01-31 23:32:56

2

您需要测试计时器或测试每个事件中执行的代码吗?如果是这样,你可以把这个逻辑放到另一个类中去测试。你可以相信定时器会叫它...