Geeks With Blogs
New Things I Learned

Every now and then, I end up writing and re-writing the same code (or very, very similar) to achieve a functionality that I’ve had before.  Sometimes I can remember where I wrote it, so I can just copy and paste.  At other times, I have to redo it again since I forgot where it was.  So I’d like to put it up on my blog so I have access to it.  If anyone else gets to see it and can use it, so much the better for everyone.  Of course, I’d also accept criticism to the code too .

So, this is my first one; because I’ve used it for awhile and I ended up having to rewrite it yet again today for a pet project that I have.  Now, I understand not everyone likes to do Unit Testing, but I enjoy it every now and then.  It is somewhat boring & tedious, but it also gives me some relaxation since I can do very, very simple code and don’t have to think too much – unit test code should not be very complex.  In most unit tests, the code will try to go through the path of the tested code and usually try to handle the happy path.  I don’t do pure Test Driven Development, but I understood some benefit of what TDD can do.

One advantage of doing TDD is that you will end up also writing tests (and code) that will verify arguments.  And since your code has argument checks, then your unit tests also have to verify both success and failure cases of those arguments.  Consider the following very simple code:

public class SomeClass
{
   public double SR(double d)
   {
      return Math.Sqrt(d);
   }
}

Essentially you just wanted a wrapper method, instead of calling the function Math.Sqrt() all the time; simple enough.  But let’s say that you also wanted to change the default behavior; such that the consuming code should never ever actually call this method with a negative number.  If it is a negative number, then you wanted to throw an exception.  Easy enough to do…

public double SR(double d)
{
   if (d < 0)
      throw new ArgumentException("Argument can't be negative!");

   return Math.Sqrt(d);
}

As you can see from the code above, the code is still trivial.  Of course, now you want to write a unit test for it; there are 2 unit tests you have to create: the successful case and the failure case.  So let’s see what the unit tests would look like the following (I’m using Visual Studio’s unit testing framework):

[TestMethod]
public void SRTest_Success()
{
   SomeClass sc = new SomeClass();
   Assert.AreEqual(sc.SR(100), 10.0);
}

[TestMethod]
public void SRTest_Failure()
{
   SomeClass sc = new SomeClass();
   try
   {
      sc.SR(-100);
      Assert.Fail();
   }
   catch (ArgumentException)
   {
   }
}

Again, simple, very trivial methods – however the failure case is rather verbose; you have to create a try-catch block (an empty catch at that too), so another way to do it is to use the ExpectedExceptionAttribute.

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void SRTest_Failure()
{
   SomeClass sc = new SomeClass();
   sc.SR(-100);
}

The problem with the above approach is that if you want to be able to catch multiple exceptions (not recommended in creating unit tests, but some people may want to cut corners ), you can’t do it – you can’t apply multiple ExpectedException attributes.  Another problem is if your unit test code is rather large, it may have other code paths where there’s an actual failure that will throw an ArgumentException which will pass the test happily but will result in a false positive.

So, I needed a way to be able to catch exceptions in the code itself, but I don’t want to write try-catch blocks all over the place.  So I came up with the following helper method to help me verify exceptions are thrown:

public class UnitTestHelper
{
   // Method accepts an action delegate, and a generic Exception type
   public static void VerifyExceptionThrown<TException>(Action action)
      where TException : Exception
   {
      // Verify arguments - action can't be null
      if (action == null)
         throw new ArgumentException("Action to test cannot be null!");

      // Verify arguments - TException cannot be of type Exception
      if (typeof(TException).Equals(typeof(Exception)))
         throw new ArgumentException("TException type cannot be of type Exception");

      // Actually call it
      try
      {
         action();
      }
      catch (TException)
      {
         return;
      }

      // If it gets here, fail the test
      Assert.Fail("Action does not throw the exception expected");
   }
}

The code above is fairly simple; the helper method accepts an Action delegate as a parameter and a generic TException type to be passed and I put in a constraint that has to derive from Exception class.  To also be nice and proper, the method also checks its parameters: the action parameter can’t be null, and the generic TException type cannot be of type Exception itself (because it’ll catch all exceptions, which won’t prove/disprove the unit test itself, but modify it as you want).  At the end, it’ll fail the unit test, since it should never hit the Assert.Fail method call.

The unit test will look like the following:

[TestMethod]
public void SRTest_Failure()
{
   SomeClass sc = new SomeClass();
   UnitTestHelper.VerifyExceptionThrown<ArgumentException>(() => sc.SR(-100));
}

[TestMethod]
public void SRTest_Failure_AnonymousDelegate()
{
   SomeClass sc = new SomeClass();
   UnitTestHelper.VerifyExceptionThrown<ArgumentException>(delegate() { sc.SR(-100); });
}

I put in 2 methods – the first one uses Lambda Expressions, which may not be used by those that are still using strictly .NET 2.0 framework only, so the second one demonstrates the same call but using anonymous methods.  If you’re strictly using .NET 2.0, the Action delegate is not available in the .NET Framework – you have to create your own. 

After understanding simple Lambda Expressions, personally for me, the unit test code is more readable, since I don’t need to look at any attributes, and the unit test code can contain further verification of exceptions thrown and also it can have further asserts.

For completeness, the code below is the unit test that tests the VerifyExceptionThrown method.  The code demonstrates the ‘eating your own dog food’ mentality: I get to use the method that I’m unit testing itself.

[TestMethod]
public void VerifyExceptionThrown_TestFailure_InvalidExceptionType()
{
   UnitTestHelper.VerifyExceptionThrown<ArgumentException>(() =>
      UnitTestHelper.VerifyExceptionThrown<Exception>(() => { }));
}

[TestMethod]
public void VerifyExceptionThrown_TestFailure_NullAction()
{
   UnitTestHelper.VerifyExceptionThrown<ArgumentException>(() =>
      UnitTestHelper.VerifyExceptionThrown<DivideByZeroException>(null));
}

[TestMethod]
public void VerifyExceptionThrown_TestFailure_ExceptionNotThrown()
{
   UnitTestHelper.VerifyExceptionThrown<AssertFailedException>(() =>
      UnitTestHelper.VerifyExceptionThrown<DivideByZeroException>(() => Debug.Assert(true)));
}

[TestMethod]
public void VerifyExceptionThrown_TestSuccess_DivideByZeroException()
{
   int i = 0;
   UnitTestHelper.VerifyExceptionThrown<DivideByZeroException>(() => i = 5 / i);
}
Posted on Thursday, November 5, 2009 9:22 AM .NET , Personal | Back to top


Comments on this post: My Coding Helpers: Verify exception thrown in Unit Test

# re: My Coding Helpers: Verify exception thrown in Unit Test
Requesting Gravatar...
That's great especially when you want to test IsNullOrEmpty or IsNullOrWhiteSpace on a string. I think it's reasonable to verify those assertions in a single test, but unit testing in visual studio doesn't the multiple exception issue. It's one of the reasons why I pick NUnit over Visual Studio.
Left by Adam on Dec 31, 2010 6:02 AM

Your comment:
 (will show your gravatar)


Copyright © Muljadi Budiman | Powered by: GeeksWithBlogs.net