• Post Calendar

    December 2012
    S M T W T F S
    « Nov   Feb »
     1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031  

Visual Studio 2012 testmc Code Snippet

Headline: This contains the code for the first code snippet I install when I have a new installation of Visual Studio along with the steps to get it into the right location.

The Result

The first time I saw this format for unit tests was in some work the Microsoft ASP.NET MVC (Model View Controller) team released. I’m sure it had roots elsewhere… I’ve not tracked those down, but I really like the idea.

Guidelines

Here are some of the concepts that are part of this test outline:

  • DO name your test so others know what it does.
  • DO have a single line in the Act. That makes it easy to understand what you are testing.
  • DO have an assert. It’s not really a test unless there is an assert.

Result

So when I type testmc snippet shortcut in my unit test file, this is what I will see (after I typed the name of the test – which is what the snippet will have you do):

Code Snippet Result
  1. [TestMethod]
  2. public void Demo_Test_5_Plus_5_Is_10()
  3. {
  4.     // Arrange
  5.     var expected = ;
  6.   
  7.     // Act
  8.     var actual = ;
  9.   
  10.     // Assert
  11.     Assert.AreEqual(expected, actual);
  12.     // Assert – No Assert, Exception expected
  13. }

So how did I get that?

The Snippet Code

Here is the actual code from a file called testmethodcommented.snippet.

Snippet File
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  3.   <CodeSnippet Format="1.0.0">
  4.     <Header>
  5.       <SnippetTypes>
  6.         <SnippetType>Expansion</SnippetType>
  7.       </SnippetTypes>
  8.       <Title>Test Method Commented</Title>
  9.       <Shortcut>testmc</Shortcut>
  10.       <Description>Code snippet for a test method with comments.</Description>
  11.       <Author>Karl Zachry</Author>
  12.     </Header>
  13.     <Snippet>
  14.       <Imports>
  15.         <Import>
  16.           <Namespace>Microsoft.VisualStudio.TestTools.UnitTesting</Namespace>
  17.         </Import>
  18.       </Imports>
  19.       <References>
  20.         <Reference>
  21.           <Assembly>Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll</Assembly>
  22.         </Reference>
  23.       </References>
  24.       <Declarations>
  25.         <Literal>
  26.           <ID>name</ID>
  27.           <ToolTip>Replace with the name of the test method</ToolTip>
  28.           <Default>MyTestMethod</Default>
  29.         </Literal>
  30.           <Literal Editable="false">
  31.             <ID>TestMethod</ID>
  32.             <Function>SimpleTypeName(global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod)</Function>
  33.           </Literal>
  34.       </Declarations>
  35.       <Code Language="csharp"><![CDATA[[$TestMethod$]
  36.         public void $name$()
  37.         {
  38.             // Arrange
  39.             var expected = $end$;
  40.           
  41.             // Act
  42.             var actual = ;
  43.           
  44.             // Assert
  45.             Assert.AreEqual(expected, actual);
  46.             // Assert – No Assert, Exception expected
  47.         }]]></Code>
  48.     </Snippet>
  49.   </CodeSnippet>
  50. </CodeSnippets>

I realize it seems long, but it if you just copy from here, it is really quite simple.

Where to Place the File

The testmethodcommented.snippet file should be placed in C:\Users\<username>\Documents\Visual Studio 2012\Code Snippets\Visual C#\My Code Snippets path. You might need to adjust the drive letter. This is the path on a Windows 8 machine.

I did this a long time ago, so I don’t know whether you need to start Visual Studio for the snippet to be recognized – if you don’t see it, then restart Visual Studio.

An Example

So here is a quick, trivial example of the file. You can see that I followed the guidelines.

Full Test Using Snippet
  1. [TestMethod]
  2. public void Demo_Test_5_Plus_5_Is_10()
  3. {
  4.     // Arrange
  5.     var expected = 10;
  6.     var a = 5;
  7.     var b = 5;
  8.  
  9.     // Act
  10.     var actual = Add(a, b);
  11.  
  12.     // Assert
  13.     Assert.AreEqual(expected, actual);
  14. }
  15.  
  16. public int Add(int a, int b)
  17. {
  18.     return a + b;
  19. }

Tests Expecting Exceptions

You’ll notice in the last example that this line was missing:

Exception Line
  1. // Assert – No Assert, Exception expected

I put both in the snippet, because on the rare occasion that I need to test for an exception, it is easier to delete the lines I don’t need than to type them. If you never test exceptions, then you might removed that line to save having to delete it.

A Poor Exception Example

So now let’s look at testing an exception. Here is a simple test that you are likely to see in documentation on the subject:

Poor Exception Test
  1. [TestMethod]
  2. [ExpectedException(typeof(NotImplementedException))]
  3. public void A_Poor_Subtract_Exception_Test()
  4. {
  5.     // Arrange
  6.     var a = GetMyANumber();
  7.     var b = 10;
  8.  
  9.     // Act
  10.     var actual = Subtract(a, b);
  11.  
  12.     // Assert – No Assert, Exception expected
  13. }
  14.  
  15. // This is usually in the resources.resx file,
  16. // but I'm putting it here just for this example.
  17. public const string SubtractNotImplentedExceptionMessage = "Subtract has not yet been implemented.";
  18.  
  19. public int Subtract(int a, int b)
  20. {
  21.     throw new NotImplementedException(SubtractNotImplentedExceptionMessage);
  22. }
  23.  
  24. public int GetMyANumber()
  25. {
  26.     throw new NotImplementedException();
  27. }

But what you’ll see is that it is the NotImplementedException from the GetMyANumber method that causes the test to pass, not the one we really expected in the unit test.

A Better Exception Example

So here is the way that I design those tests. There are other ways. One might ask, “Why not just stop at the Assert and forget the ExpectedException attribute all together?” I think it improves the readability that what you’re really expecting from the test it the Exception. All a matter of taste…

With with this test, if GetMyANumber throws an execption, the test will Fail because it is not the exception we were expecting.

A Better Exception Test
  1. [TestMethod]
  2. [ExpectedException(typeof(NotImplementedException))]
  3. public void A_Better_Subtract_Exception_Test()
  4. {
  5.     // Arrange
  6.     var expected = SubtractNotImplentedExceptionMessage;
  7.     try
  8.     {
  9.         var a = GetMyANumber();
  10.         var b = 10;
  11.  
  12.         // Act
  13.         var result = Subtract(a, b);
  14.  
  15.         // Assert
  16.     }
  17.     catch (NotImplementedException ex)
  18.     {
  19.         var actual = ex.Message;
  20.         Assert.AreEqual(expected, actual);
  21.         throw;
  22.     }
  23.  
  24.     // Assert – No Assert, Exception expected
  25. }

I hope this helps you right unit tests quickly but with high standards.

3 Comments  »

  1. Karthik N says:

    I may have understood this part differently… wouldn’t the “Better Exception Test” pass if GetMyANumber() threw a NotImplementedException instead of returning a number? Both tests would pass in this case.

    • karlz says:

      You are correct. When blogging I pasted the code, then realized the test didn’t pass so I moved the “try” line up. However, I forgot to re-paste my code. I’ve done that now, so the better test will now fail even if the GetMyANumber() method throws an exception of the same type. Thanks for the correction.

  2. Alexander M. Batishchev says:

    Also you can use library like FluentAssertions:
    Action action = () => Subtract(a, b);
    action.ShouldThrow():

    Also NUnit supports Assert.Throws(action);

RSS feed for comments on this post, TrackBack URI

Leave a Comment