Introduction
This tip considers how best to replace System.Timer
with a mock object to allow methods that use the timer to be tested effectively.
Why Create a Mock Timer?
It’s difficult to meet the basic requirements for a unit test if the method has an active timer as a dependency. It’s generally accepted that Unit tests should be executed entirely in memory, be self-contained and be exactly repeatable. But the Timer
uses the system timer so the test is not self-contained, neither is it in a constant state as the timer is busy counting down some variable. If it’s not exactly repeatable, a different test is being run each time and, if it depends upon an external item it is, at least in part, an integration test of whatever it interfaces with.
What Exactly is Being Tested?
An important consideration is that the Timer
itself is not being tested. What is tested is how the Timer
interacts with the object under test (by way of firing the Elapsed
event) and also how the object under test interacts with the timer through the timer’s various setup methods and action commands.
Constructing an ITimer Interface
Unit testing would be very easy to do if System.Timer
implemented an interface (ITimer
) that exposed the timer’s public
methods, properties and events. All that would need to be done is to code using the ITimer
interface and then employ a mock ITimer
instance when testing. But Timer
does not explicitly implement that sort of interface so it’s necessary to write your own. Something like:
public interface ITimer
{
#region Public Events
event ElapsedEventHandler Elapsed;
#endregion
#region Public Properties
double Interval { get; set; }
#endregion
#region Public Methods and Operators
void Dispose();
void Start();
void Stop();
#endregion
}
Running the Tests
Even with the ITimer
interface in place, you can’t write:
ITimer myTimer= new System.Timer();
As the system.Timer
does not explicitly implement the ITimer
interface, to get around this problem, it’s necessary to define a subclass of Timer
that implements ITimer
. Something like this:
public class WatchDogTimer : Timer, ITimer { }
The derived timer (WatchDogTimer
) explicitly implements the ITimer
interface and has inherited all the functionality of the System.Timer
. It’s now possible to do tests like this:
[TestMethod]
public void SetAlarm_SetsTimerInterval_To_INTERVAL_ThenCalls_TimerStart()
{
const int INTERVAL=6;
IBell bell = Substitute.For<IBell>();
ITimer timer = Substitute.For<ITimer>();
Alarm alarm = new Alarm(timer, bell);
alarm.SetAlarm(INTERVAL);
Received.InOrder(() =>
{
timer.Interval = INTERVAL;
timer.Start();
});
}
[TestMethod]
public void TimerLapsedEvent_Results_In_A_CallTo_BellRing()
{
IBell bell = Substitute.For<IBell>();
ITimer timer = Substitute.For<ITimer>();
Alarm alarm = new Alarm(timer, bell);
timer.Elapsed += Raise.Event<ElapsedEventHandler>(this, null);
bell.Received().Ring();
}
One Last Thing
There is a downside to this approach, the intelliSense that usually accompanies the System.Timer
is lost, but with descriptive method names like Start
and Stop
, that’s not such a big deal.