How to unit test a timer based on System.Threading.Timer in .NET The System.Threading.Timer has a callback method
A timer invokes its methods when its due time elapses, and invokes its methods once per period thereafter. You can use the Change method of the Timer class to change these values, or disable the timer. You can use the Dispose method of the Timer class to free the resources when a timer is no longer needed.
No, a timer runs in the thread in which it was created.
Timer is not thread-safe. Since then this has been repeated on blogs, in Richter's book "CLR via C#", on SO, but this is never justified.
Timers. Timer raises the elapsed event, is it raised in an independent thread? Yes, they run in a different thread. The System.
You can unit-test it by not actually creating a direct dependency on System.Threading.Timer
. Instead, create an ITimer
interface, and a wrapper around System.Threading.Timer
that implements it.
First you need to convert the callback to an event, so that it can be made part of an interface:
public delegate void TimerEventHandler(object sender, TimerEventArgs e);
public class TimerEventArgs : EventArgs
{
public TimerEventArgs(object state)
{
this.State = state;
}
public object State { get; private set; }
}
Then create an interface:
public interface ITimer
{
void Change(TimeSpan dueTime, TimeSpan period);
event TimerEventHandler Tick;
}
And a wrapper:
public class ThreadingTimer : ITimer, IDisposable
{
private Timer timer;
public ThreadingTimer(object state, TimeSpan dueTime, TimeSpan period)
{
timer = new Timer(TimerCallback, state, dueTime, period);
}
public void Change(TimeSpan dueTime, TimeSpan period)
{
timer.Change(dueTime, period);
}
public void Dispose()
{
timer.Dispose();
}
private void TimerCallback(object state)
{
EventHandler tick = Tick;
if (tick != null)
tick(this, new TimerEventArgs(state));
}
public event TimerEventHandler Tick;
}
Obviously you would add whatever overloads of the constructor and/or Change
method you need to use from the Threading.Timer
. Now you can unit test anything depending on ITimer
with a fake timer:
public class FakeTimer : ITimer
{
private object state;
public FakeTimer(object state)
{
this.state = state;
}
public void Change(TimeSpan dueTime, TimeSpan period)
{
// Do nothing
}
public void RaiseTickEvent()
{
EventHandler tick = Tick;
if (tick != null)
tick(this, new TimerEventArgs(state));
}
public event TimerEventHandler Tick;
}
Whenever you want to simulate a tick, just call RaiseTickEvent
on the fake.
[TestMethod]
public void Component_should_respond_to_tick
{
ITimer timer = new FakeTimer(someState);
MyClass c = new MyClass(timer);
timer.RaiseTickEvent();
Assert.AreEqual(true, c.TickOccurred);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With