• Post Calendar

    November 2012
    S M T W T F S
    « Sep   Dec »
     123
    45678910
    11121314151617
    18192021222324
    252627282930  

Where is TestContext.BeginTimer()?

This post outlines my (with help of others) solution to keeping my unit tests working in the absence of TestContext.BeginTimer() and TestContext.EndTimer(). These seem to be missing in Visual Studio 2012 and I can’t find any posts… so I assume no one else uses this pattern.

What’s Broken?

Here is a sample unit test that demonstrates the problem. It’s a very simple test:

The Broken Test
  1. [TestMethod]
  2. public void Simple_TestContext_TimeingTest()
  3. {
  4.     // Arrange
  5.     var timerName = TestContext.TestName;
  6.  
  7.     // Act
  8.     TestContext.BeginTimer(timerName);
  9.  
  10.     // Assert
  11.     Thread.Sleep(100);
  12.     TestContext.EndTimer(timerName);
  13. }

When I run that test in Visual Studio 2012 I get the following:

image

What? A System.NotSupportedException: Specified method is not supported? It worked fine in previous versions of Visual Studio. As I said, I have lots of tests like this.

What Should I Do Now?

I routinely used these two methods to look at performance between alternative approaches. When I upgraded to Visual Studio 2012 I got a Method Not Supported exception. So I wondered if I should update all my tests to instead use a System.Diagnostics.Stopwatch, or if I should develop a derived class from TestContext and implemented the methods. I chose the later.

Deriving from TestContext

The post “How do I derive from TestContext class and implement from base members” provided the information I needed to get started. While snotman’s  motivations were different, a twist on his approach was just what I needed to keep this change short.
So here is the critical portion of my class that does that:

TestContextWithTimer
  1. public class TestContextWithTimer : TestContext
  2. {
  3.     private TestContext _contextInstance;
  4.  
  5.     private Dictionary<string, Stopwatch> _stopwatches;
  6.  
  7.     public Dictionary<string, Stopwatch> Stopwatches
  8.     {
  9.         get { return _stopwatches ?? (_stopwatches = new Dictionary<string, Stopwatch>()); }
  10.     }
  11.  
  12.  
  13.     public TestContextWithTimer(TestContext context)
  14.     {
  15.         _contextInstance = context;
  16.     }
  17.  
  18.     public override void AddResultFile(string fileName)
  19.     {
  20.         _contextInstance.AddResultFile(fileName);
  21.     }
  22.  
  23.     public override void BeginTimer(string timerName)
  24.     {
  25.         Console.WriteLine("Timer Name: " + timerName);
  26.         if (!Stopwatches.ContainsKey(timerName))
  27.             Stopwatches.Add(timerName, new Stopwatch());
  28.         _stopwatches[timerName].Start();
  29.         Console.WriteLine("Start Time: " + DateTime.Now);
  30.     }
  31.  
  32.     public override System.Data.Common.DbConnection DataConnection
  33.     {
  34.         get { return _contextInstance.DataConnection; }
  35.     }
  36.  
  37.     public override System.Data.DataRow DataRow
  38.     {
  39.         get { return _contextInstance.DataRow; }
  40.     }
  41.  
  42.     public override void EndTimer(string timerName)
  43.     {
  44.         if (!Stopwatches.ContainsKey(timerName))
  45.             throw new InvalidOperationException();
  46.         Stopwatches[timerName].Stop();
  47.         Console.WriteLine("End Time: " + DateTime.Now);
  48.         Console.WriteLine("Timer Duration: " + Stopwatches[timerName].Elapsed);
  49.     }

So with that code I rewrote the original test to look like this:

The New Unit Test
  1. [TestClass]
  2. public class TimingTest
  3. {
  4.  
  5.     public TestContext TestContext { get; set; }
  6.  
  7.     public TestContextWithTimer TestContextWithTimer { get; set; }
  8.  
  9.     [TestInitialize]
  10.     public void Initialize()
  11.     {
  12.         TestContextWithTimer = new TestContextWithTimer(TestContext);
  13.     }
  14.  
  15.     [TestMethod]
  16.     public void Simple_TestContextWithTimer_TimeingTest()
  17.     {
  18.         // Arrange
  19.         var timerName = TestContextWithTimer.TestName;
  20.  
  21.         // Act
  22.         TestContextWithTimer.BeginTimer(timerName);
  23.  
  24.         // Assert
  25.         Thread.Sleep(100);
  26.         TestContextWithTimer.EndTimer(timerName);
  27.     }

That yielded these results instead:

image

Now I’m not sure what would happen if you have complicated cases with overlapping timers. However, for my unit tests this met my needs. So I’ll be writing this, now that I’ve proved it in some simple tests, to help me get past the strange missing capability in Visual Studio 2012.

I hope this helps others that might be facing this issue.

Cheers – Karl

9 Comments  »

  1. Kashif says:

    I think you must have something to do with either configuration or installation.

    I just tested the same thing and it works for me.

    TestContext.BeginTimer(“mytest”);
    System.Threading.Thread.Sleep(5 * 1000);
    TestContext.EndTimer(“mytest”);

    and here is the out put

    Timer Results:
    Timer Name: mytest
    Start Time: 11/26/2012 11:16:18 PM
    End Time: 11/26/2012 11:16:23 PM
    Timer Duration: 00:00:05.0007454

    • karlz says:

      I’m on Visual Studio 2012 installed on Windows 8 Pro x64. You’re on VS 2012?

      • Rafał Wojciechowski says:

        After project is upgraded, old dll references are used. I had exactly the same issues. Make sure that references for UnitTestFramework and LoadTestFramework point to IDE/PublicAssemblies (not ReferenceAssemblies).

        • karlz says:

          Thanks so much! I’ve not had a chance to try it yet, but that makes a lot of sense. And that explains why some posters here didn’t have the issue. Some were upgrading as I was, others (without the issue) weren’t.
          I hope your comment helps others too.

  2. Charlesdwm says:

    According to the following Microsoft blog, http://blogs.msdn.com/b/geoffgr/archive/2014/08/05/adding-timers-to-coded-ui-tests-running-in-load-tests.aspx, the ability to use timers in a Unit test was removed from Visual Stuido 2012. The blog states that the timer still works when a unit test is placed inside a load test, but standalone, the unit test will throw the System.NotSupportedException. The blog states that a workaround is to use the following line of code just before the beginTimer() call:

    if (TestContext.Properties.Contains(“$LoadTestUserContext”)) //running as load
    textContextInstance.BeginTimer(“MyTimerName”);

    This approach is working on my installation of VS2012, and allows me to have the timers in my unit test and to run it as a single user without putting it in a load test. Removing the functionality in CS 2012 was NOT a swift move by Microsoft. I have found some cases where a timer in unit tests still does not work in VS 2013, but then sometimes it will work in 2013. In any case, in VS 2012, “unit test timers” are consistently broken but the above line of code provides a workaround.

  3. Fred F. says:

    I added the public reference, but still get the not-supported exception. I created a new test project and compare the new to my existing. There are definitely reference and build differences. From my limited knowledge of MSBuild, It looks like running the tests in VS2010 will use the correct assembly.

RSS feed for comments on this post, TrackBack URI

Leave a Comment