At some point, you will need to put a timer into your C# code. Hopefully you're doing Test Driven Development, or at least unit testing, to cover your need for a timer with a unit test. If you are - I'm betting you ran into some really ugly problems like tests that would not pass without having 'Thread.Sleep(1000)' calls in them. Worse yet - last week, I put a 3 second timer into a class that was being unit tested. This one mistake cause my CruiseControl build to go from 2 minutes, to timing out at 90 minutes because NUnit was keeping the app domain alive while the timer was alive, so it never closed the test run. Oops.
To fix this problem, we decided we needed to eliminate the use of an actual timer and use an abstraction that could be mocked/controlled in our unit tests. Unfortunately, the .NET Framework does not have an actual abstraction for a timer. So, if you need to use a timer in your code - and at some point in time, you will - you'll want to create a very simple ITimer interface that would let you control when the timer elapses and fires its registered action.
Here's the core of the abstraction that we came up with, initially.
public interface ITimer
{
void Start(Action timerAction);
}
With such a simple interface in place, we can now mock it out in our unit tests (I like Rhino Mocks) and set up an expectation on the Start method to capture the timerAction parameter, then simulate the timer elapsing by calling the timer action from our unit test. Here's an example test and 'system under test' to illustrate how we use this interface.
[Test]
public void DemonstratingHowToUnitTestATimerElapsing()
Action timerElaspedAction;
ITimer timer = MockRepository.GenerateMock<ITimer>();
timer.Expect(t => t.Start(null)).IgnoreArguments().Callback(
delegate(Action timerAction)
timerElapsedAction = timerAction;
return true;
});
MySystemUnderTest sut = new MySystemUnderTest();
sut.StartMonitoringStuff(timer);
//here's where we simulate the timer elapsing
timerElapsedAction();
Assert.IsTrue(sut.TheTimerActionWasCalled);
public class MySystemUnderTest()
public bool TheTimerActionWasCalled { get; set; }
public MySystemUnderTest()
TheTimerActionWasCalled = false;
public StartMonitoringStuff(ITimer timer)
timer.Start(() => TheTimerActionWasCalled = true);
There is a bit more detail to the actual ITimer interface, and the implementation, though. We ran into issues where we needed to stop the timer, prevent it from firing after we close the SUT, etc. So, all said and done, here's the full ITimer interface and MyTimer implementation that we ended up with.
void Start(Action action);
void Stop();
public class MyTimer : ITimer, IDisposable
private TimeSpan _timerInterval;
private Timer _timer;
private Action _timerAction;
private bool IsRunning { get; set; }
public MyTimer(TimeSpan timerInterval)
_timerInterval = timerInterval;
public void Dispose()
StopTimer();
public void Start(Action action)
_timerAction = action;
IsRunning = true;
StartTimer();
public void Stop()
IsRunning = false;
private void StartTimer()
_timer = new Timer(o => Timer_Execute(), null, 0, Convert.ToInt32(_timerInterval.TotalMilliseconds));
private void StopTimer()
if (_timer != null)
_timer.Change(Timeout.Infinite, Timeout.Infinite);
_timer.Dispose();
_timer = null;
private void Timer_Execute()
try
_timerAction();
finally
if (IsRunning)
This has worked out very well for us, so far. It lets us put a timer in place when we need one, but not worry about thread racing issues, long running tests, etc.
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.