How to use Assert (or other Test classes?) To verify that an exception was thrown?
#1st floor
Well, I can almost sum up what everyone else said before... Anyway, here is the code I built based on the good answer:) the rest is to copy and use
/// <summary> /// Checks to make sure that the input delegate throws a exception of type TException. /// </summary> /// <typeparam name="TException">The type of exception expected.</typeparam> /// <param name="methodToExecute">The method to execute to generate the exception.</param> public static void AssertRaises<TException>(Action methodToExecute) where TException : System.Exception { try { methodToExecute(); } catch (TException) { return; } catch (System.Exception ex) { Assert.Fail("Expected exception of type " + typeof(TException) + " but type of " + ex.GetType() + " was thrown instead."); } Assert.Fail("Expected exception of type " + typeof(TException) + " but no exception was thrown."); }
#2nd floor
@The helper provided by Richiban works well, except that it does not handle throwing exceptions, but does not handle the expected types. The following are involved:
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace YourProject.Tests { public static class MyAssert { /// <summary> /// Helper for Asserting that a function throws an exception of a particular type. /// </summary> public static void Throws<T>( Action func ) where T : Exception { Exception exceptionOther = null; var exceptionThrown = false; try { func.Invoke(); } catch ( T ) { exceptionThrown = true; } catch (Exception e) { exceptionOther = e; } if ( !exceptionThrown ) { if (exceptionOther != null) { throw new AssertFailedException( String.Format("An exception of type {0} was expected, but not thrown. Instead, an exception of type {1} was thrown.", typeof(T), exceptionOther.GetType()), exceptionOther ); } throw new AssertFailedException( String.Format("An exception of type {0} was expected, but no exception was thrown.", typeof(T)) ); } } } }
#3rd floor
If you use NUNIT, you can do this:
Assert.Throws<ExpectedException>(() => methodToTest());
You can also store the thrown exception to further verify it:
ExpectedException ex = Assert.Throws<ExpectedException>(() => methodToTest()); Assert.AreEqual( "Expected message text.", ex.Message ); Assert.AreEqual( 5, ex.SomeNumber);
See: http : //nunit.org/docs/2.5/exceptionAsserts.html
#4th floor
I don't recommend using the ExpectedException attribute (because it's too restrictive and error prone) or writing a try / catch block in each test (because it's too complex and error prone). Use well-designed assertion methods - provided or written by the test framework. This is what I wrote and used.
public static class ExceptionAssert { private static T GetException<T>(Action action, string message="") where T : Exception { try { action(); } catch (T exception) { return exception; } throw new AssertFailedException("Expected exception " + typeof(T).FullName + ", but none was propagated. " + message); } public static void Propagates<T>(Action action) where T : Exception { Propagates<T>(action, ""); } public static void Propagates<T>(Action action, string message) where T : Exception { GetException<T>(action, message); } public static void Propagates<T>(Action action, Action<T> validation) where T : Exception { Propagates(action, validation, ""); } public static void Propagates<T>(Action action, Action<T> validation, string message) where T : Exception { validation(GetException<T>(action, message)); } }
Example use:
[TestMethod] public void Run_PropagatesWin32Exception_ForInvalidExeFile() { (test setup that might propagate Win32Exception) ExceptionAssert.Propagates<Win32Exception>( () => CommandExecutionUtil.Run(Assembly.GetExecutingAssembly().Location, new string[0])); (more asserts or something) } [TestMethod] public void Run_PropagatesFileNotFoundException_ForExecutableNotFound() { (test setup that might propagate FileNotFoundException) ExceptionAssert.Propagates<FileNotFoundException>( () => CommandExecutionUtil.Run("NotThere.exe", new string[0]), e => StringAssert.Contains(e.Message, "NotThere.exe")); (more asserts or something) }
note
It's a reasonable idea to return exceptions instead of supporting validation callbacks, except that doing so makes the invocation syntax of this assertion very different from other assertions I use.
Unlike others, I use 'propagates' instead of' throws' because we can only test whether exceptions propagate from calls. We can't test throwing exceptions directly. But I think you can make the projection image mean: throw instead of being caught.
Last thought
Before switching to this method, I consider using the ExpectedException attribute, if more validation is needed when the test only validates the exception type and uses the try / catch block. However, I have to not only consider which technology each test uses, but also change the code from one technology to another when it needs to change. Using a consistent approach can save energy.
All in all, this method of exercise: ease of use, flexibility and robustness (hard to do wrong).
#5th floor
You can download the package from Nuget using the following command: PM > install package mstetextensions, which adds the nUnit / xUnit style Assert.Throws() syntax to MsTest.
Advanced instructions: download the assembly and inherit from BaseTest, you can use the Assert.Throws() syntax.
The main methods of implementing Throws are as follows:
public static void Throws<T>(Action task, string expectedMessage, ExceptionMessageCompareOptions options) where T : Exception { try { task(); } catch (Exception ex) { AssertExceptionType<T>(ex); AssertExceptionMessage(ex, expectedMessage, options); return; } if (typeof(T).Equals(new Exception().GetType())) { Assert.Fail("Expected exception but no exception was thrown."); } else { Assert.Fail(string.Format("Expected exception of type {0} but no exception was thrown.", typeof(T))); } }
Disclosure: I put this bag together.
More information: http : //www.bradoncode.com/blog/2012/01/asserting-exceptions-in-mstest-with.html