Simplify Time Measurement in Tests and Debug Code
A simple helper class I derived from a more generic pattern: For debugging and testing, I quite often want to measure the time used for a given process. Usually, this looks somewhat like this:
public void TestElapsedTime() { DateTime start = DateTime.Now; //do some work DateTime end = DateTime.Now; double elapsedTime = end.Subtract(start).TotalMilliseconds; Console.Out.WriteLine("Work took {0} milliseconds", elapsedTime); }
However: The code above, while being pretty simple, can be easily wrapped into a generic helper class:
/// <summary> /// A guard that can be used to measure the time /// used for a given process by simply wrapping it /// in a using statement. /// </summary> public class TimeGuard : IDisposable { private readonly Action<double> action; private readonly DateTime startTime; /// <summary> /// Creates the guard with a given action that receives the /// elapsed time in milliseconds. /// </summary> /// <param name="setDelta">The action that is being invoked /// with time (in milleconds) that was taken between construction /// of this instance until disposal.</param> /// <exception cref="ArgumentNullException">If <paramref name="setDelta"/> /// is a null reference.</exception> public TimeGuard(Action<double> setDelta) { if (setDelta == null) throw new ArgumentNullException("setDelta"); action = setDelta; startTime = DateTime.Now; } /// <summary> /// Calculates the elapsed time since construction /// and submits the delta to the <see cref="action"/> /// action. /// </summary> public void Dispose() { var now = DateTime.Now; action(now.Subtract(startTime).TotalMilliseconds); } }
Using the TimeGuard class, I can perform time measurements without having to deal with DateTime instances and the calculation of the elapsed time at all. Two samples:
public void TestElapsedTime() { double elapsedTime = 0; using (new TimeGuard(t => elapsedTime = t)) { //do some work } Console.Out.WriteLine("Work took {0} milliseconds", elapsedTime); }
[Test] public void TestElapsedTime() { using (new TimeGuard(t => Assert.Less(t, 500))) { //do some work here that should take less than 500 ms } }
Apart from providing cleaner code, I also prefer this approach because it encapsulates time measurement functionality in a single class and simplifies adjustments, like using a different pattern to retrieve time stamps, or using the StopWatch class to get a more accurate measurement (thanks to Simone Chiaretta for the hint).