Home > C#, Testing > Simplify Time Measurement in Tests and Debug Code

Simplify Time Measurement in Tests and Debug Code

February 23rd, 2009

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).


Author: Categories: C#, Testing Tags:
  1. February 24th, 2009 at 09:54 | #1

    You should use the StopWatch class instead of the DateTime since it’s a more precise timer and doesn’t have the same activation cost that might influence the actual timing.

  2. February 24th, 2009 at 10:02 | #2

    Simone,

    Thanks for your comment – I’ve included a link to the StopWatch class in the article. As a matter of fact, I’m using neither of these – my own implementation relies on a variant of Ayende’s SystemTime class (see link in the article) but I felt the sample in the article is more accessible for most readers.

    But that’s the nice thing about encapsulation – it only takes you a few seconds to switch to your own implementation :-)

    Cheers,
    Philipp

  3. March 4th, 2009 at 22:25 | #3

    A very cunning use of IDisposable! I also quite like the way you use an action to invoke an Assert. Very cunning indeed :-)

    Colin E.

  4. March 5th, 2009 at 13:31 | #4

    thx Colin :)

  5. March 3rd, 2010 at 12:32 | #5

    Simone’s already observed that you should use StopWatch (and she’s right). However, if you’re going to stick with DateTime.Now you should really switch it to DateTime.UtcNow. The non-UTC version is hideously slow (use Reflector to look at the code it manages to end up invoking if you don’t believe me).

  1. May 5th, 2011 at 19:50 | #1
  2. October 6th, 2011 at 17:03 | #2