Skip to content

Update failure message of Assert.Throws* to include stacktrace of actual exception #9190

Description

@drieseng

Summary

When an Assert.Throws* method fails, the failure message includes (duplicate) information of the expected and actual exception (type):

Assertion failed. Expected exception of exact type NotSupportedException but caught InvalidOperationException.

expected type:    System.NotSupportedException
actual type:      System.InvalidOperationException
actual exception: System.InvalidOperationException: C

Assert.ThrowsExactly<NotSupportedException>(Do)
   at DogFood.ThrowTest.ThrowsExactlyFailure() in C:\git\github\MSTestDogFood\test\ThrowTest.cs:line 22
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

It would be nice if the failure message included the stacktrace (or the result of `Exception.ToString()) of the exception that was thrown.

In the end, it's an exception that you did not expect. I'm sure people are interested to known the full details of that exception.

To reproduce, compile and run the following test:

using System;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DogFood;

[TestClass]
public sealed class ThrowTest
{
    [TestMethod]
    public void ThrowsExactlyFailure()
    {
        _ = Assert.ThrowsExactly<NotSupportedException>(Do);
    }

    private static void Do()
    {
        string x = null;

        try
        {
            // Force an NRE
            _ = x.Normalize();
        }
        catch (Exception e1)
        {
            try
            {
                throw new ArgumentException("B", e1);
            }
            catch (Exception e2)
            {
                throw new InvalidOperationException("C", e2);
            }
        }
    }
}

Expected result:

Assertion failed. Expected exception of exact type NotSupportedException but caught InvalidOperationException.

Actual exception:
System.InvalidOperationException: C
 ---> System.ArgumentException: B
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at DogFood.ThrowTest.Do() in ...
   --- End of inner exception stack trace ---
   at DogFood.ThrowTest.Do() in ...
   --- End of inner exception stack trace ---
   at DogFood.ThrowTest.Do() in ...
   at DogFood.ThrowTest.ThrowsExactlyFailure() in ...

Assert.ThrowsExactly<NotSupportedException>(Do)
   at DogFood.ThrowTest.ThrowsExactlyFailure() in C:\git\github\MSTestDogFood\test\ThrowTest.cs:line 13
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

Note that I also removed duplicate infomation from the failure message. Feel free to ignore.

Actual result: (with version 4.3.0-preview.26309.1)

Assertion failed. Expected exception of exact type NotSupportedException but caught InvalidOperationException.

expected type:    System.NotSupportedException
actual type:      System.InvalidOperationException
actual exception: System.InvalidOperationException: C

Assert.ThrowsExactly<NotSupportedException>(Do)
   at DogFood.ThrowTest.ThrowsExactlyFailure() in C:\git\github\MSTestDogFood\test\ThrowTest.cs:line 13
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

The above was the output using version 2026.1.2 of ReSharper's test runner.
Test Explorer version 18.6.1 produces the following output:

  Message: 
Assertion failed. Expected exception of exact type NotSupportedException but caught InvalidOperationException.

expected type:    System.NotSupportedException
actual type:      System.InvalidOperationException
actual exception: System.InvalidOperationException: C

Assert.ThrowsExactly<NotSupportedException>(Do)

  Stack Trace: 
ThrowTest.ThrowsExactlyFailure() line 13
MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/assertionAssert / StringAssert / CollectionAssert APIs.area/mstestMSTest framework (not analyzers or assertions).

    Fields

    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions