How do I use Assert to verify that an exception was thrown?

Posted by DefunctExodus on Fri, 20 Dec 2019 09:48:10 +0100

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

Topics: Attribute REST