Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit test System.Threading.Timer in .NET

How to unit test a timer based on System.Threading.Timer in .NET The System.Threading.Timer has a callback method

like image 372
Ghassan Karwchan Avatar asked Mar 02 '10 22:03

Ghassan Karwchan


People also ask

How to use System threading timer in C#?

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.

Does timer create new thread C#?

No, a timer runs in the thread in which it was created.

Is system threading timer thread safe?

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.

Does system timers timer run in a separate thread?

Timers. Timer raises the elapsed event, is it raised in an independent thread? Yes, they run in a different thread. The System.


1 Answers

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);
}
like image 150
Aaronaught Avatar answered Oct 23 '22 00:10

Aaronaught