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:
- [TestMethod]
- public void Simple_TestContext_TimeingTest()
- {
- // Arrange
- var timerName = TestContext.TestName;
- // Act
- TestContext.BeginTimer(timerName);
- // Assert
- Thread.Sleep(100);
- TestContext.EndTimer(timerName);
- }
When I run that test in Visual Studio 2012 I get the following:
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:
- public class TestContextWithTimer : TestContext
- {
- private TestContext _contextInstance;
- private Dictionary<string, Stopwatch> _stopwatches;
- public Dictionary<string, Stopwatch> Stopwatches
- {
- get { return _stopwatches ?? (_stopwatches = new Dictionary<string, Stopwatch>()); }
- }
- public TestContextWithTimer(TestContext context)
- {
- _contextInstance = context;
- }
- public override void AddResultFile(string fileName)
- {
- _contextInstance.AddResultFile(fileName);
- }
- public override void BeginTimer(string timerName)
- {
- Console.WriteLine("Timer Name: " + timerName);
- if (!Stopwatches.ContainsKey(timerName))
- Stopwatches.Add(timerName, new Stopwatch());
- _stopwatches[timerName].Start();
- Console.WriteLine("Start Time: " + DateTime.Now);
- }
- public override System.Data.Common.DbConnection DataConnection
- {
- get { return _contextInstance.DataConnection; }
- }
- public override System.Data.DataRow DataRow
- {
- get { return _contextInstance.DataRow; }
- }
- public override void EndTimer(string timerName)
- {
- if (!Stopwatches.ContainsKey(timerName))
- throw new InvalidOperationException();
- Stopwatches[timerName].Stop();
- Console.WriteLine("End Time: " + DateTime.Now);
- Console.WriteLine("Timer Duration: " + Stopwatches[timerName].Elapsed);
- }
So with that code I rewrote the original test to look like this:
- [TestClass]
- public class TimingTest
- {
- public TestContext TestContext { get; set; }
- public TestContextWithTimer TestContextWithTimer { get; set; }
- [TestInitialize]
- public void Initialize()
- {
- TestContextWithTimer = new TestContextWithTimer(TestContext);
- }
- [TestMethod]
- public void Simple_TestContextWithTimer_TimeingTest()
- {
- // Arrange
- var timerName = TestContextWithTimer.TestName;
- // Act
- TestContextWithTimer.BeginTimer(timerName);
- // Assert
- Thread.Sleep(100);
- TestContextWithTimer.EndTimer(timerName);
- }
That yielded these results instead:
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
Leave a Reply