While it is an easy and (thread) safe alternative to wrap the test code in a lambda like Kip's answer I've found that it makes the stack trace a little harder to read since you'll always have the anonomous labmda stuck in there. Also, it requires another nesting level and it just tickles my OCD nerves a little.
I'd love for this to be extensible in MSTest, and in something like XUnit or NUnit you can get around this. You could even do this Aspect Oriented by superimposing a wrapper method around each method being run using something like PostSharp (see here).
If you're stuck with MSTest for whatever reasons (we've got a few myself, "attaching" files, CI scripts having been setup etc) you could do this though.
Make use of the FirstChanceException which will catch any exception thrown. Now, what I propose here is not thread safe and a bit wacky but if you're like us, running single threaded tests and care more about ease of use than performance etc it might work for you, you could improve this by bundling the registrations etc with the test context.
Basically, what I did anyway is to have a global test class that hooks the FirstChanceExceptions and 'safekeeps' the last thrown exception, then I reference this in the cleanup method.
[TestClass]
public static class GlobalSetup
{
[AssemblyInitialize]
public static void Setup(TestContext context)
{
AppDomain.CurrentDomain.FirstChanceException += (s, e) => LastException = e.Exception;
}
public static Exception LastException { get; private set; }
}
Then in a base class which contains logic for cleaning up any test:
[TestCleanup]
public virtual void Cleanup()
{
if (TestContext.CurrentTestOutcome != UnitTestOutcome.Passed && GlobalSetup.LastException != null)
{
var e = GlobalSetup.LastException;
Log.Error(GlobalSetup.LastException, $"{e.GetType()}: {e.Message}
{e.StackTrace}");
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…