Friday, November 18, 2016

Testing Exception Messages with MS Test

I usually use NUnit to do my C# unit tests, but when I need to use the Microsoft Fakes framework I have to use the built-in (to Visual Studio) MS Test framework.  This is because Fakes requires instrumentation ability that NUnit just doesn't have.  It also means I can't use the Resharper test runner like I normally do.  Neither of those changes is usually a problem, but today I found out that testing an exception message in MS Test is actually a bit tricky.

You can use the
[ExpectedException]
attribute around a test to indicate to MS Test that you expect that test to throw an exception. However, even though there is an overload for that attribute that accepts a message, it's not actually used to test whether the thrown exception has the message you specify in the attribute. So
[ExpectedException(typeof(ArgumentNullException), "A name is required")]
doesn't actually check whether the message on the exception is
"A name is required"
. Instead, if that test fails (which would happen if an exception wasn't thrown since you're expecting that one will be thrown) the text that will appear in Test Explorer is
"A name is required"
. The good news is that there's an easy way around this. The bad news is you still have to create your own attribute to do it. It's not complicated. h/t to BlackjacketMack on SO for posting his solution here.

   1:  public class ExpectedExceptionWithMessageAttribute : ExpectedExceptionBaseAttribute
   2:  {
   3:      public Type ExceptionType { get; set; }
   4:   
   5:      public string ExpectedMessage { get; set; }
   6:   
   7:      public ExpectedExceptionWithMessageAttribute(Type exceptionType)
   8:      {
   9:          ExceptionType = exceptionType;
  10:      }
  11:   
  12:      public ExpectedExceptionWithMessageAttribute(Type exceptionType, string message)
  13:      {
  14:          ExceptionType = exceptionType;
  15:          ExpectedMessage = message;
  16:      }
  17:   
  18:      protected override void Verify(Exception exception)
  19:      {
  20:          if (exception.GetType() != ExceptionType)
  21:          {
  22:              NUnit.Framework.Assert.Fail(
  23:                  "ExpectedExceptionWithMessageAttribute failed. Expected exception type: {0}. Actual exception type: {1}. Exception message: {2}",
  24:                  ExceptionType.FullName, exception.GetType().FullName, exception.Message);
  25:          }
  26:   
  27:          var actualMessage = exception.Message.Trim();
  28:   
  29:          if (ExpectedMessage != null)
  30:          {
  31:              Assert.AreEqual(ExpectedMessage, actualMessage);
  32:          }
  33:      }
  34:  }

You use it just like you used
[ExpectedException]
earlier.
[ExpectedExceptionWithMessage(typeof(ArgumentNullException), "A name is required")]

No comments:

Post a Comment