mstest异常处理方法

Method for handling exceptions in mstest

我有很多以这种格式编写的测试:

[TestMethod]
public void TestMethod1()
{
    try
    {
        DoShomething();
    }
    catch (Exception e)
    {
        WriteExceptionLogWithScreenshot( e );
    }
}

[TestMethod]
public void TestMethod2()
{
    try
    {
        DoAnotherShomething();
    }
    catch ( Exception e )
    {
        WriteExceptionLogWithScreenshot( e );
    }
}

我想使用类似

的东西来统一这个异常处理
[TestCleanup]
public void Cleanup()
{
    // find out if an exception was thrown and run WriteExceptionLogWithScreenshot( e )
}

那么我就可以避免在所有方法中编写 try catch 块。

mstest支持这样的东西吗?有人知道我能做什么吗?

这个更简单:

    private void TryTest(Action action)
    {
        try
        {
            action();
        }
        catch (Exception e)
        {
            WriteExceptionLogWithScreenshot(e);
            throw;
        }
    }

    [TestMethod]
    public void TestMethod1()
    {
        TryTest(new Action(() =>
        {
            DoSomething();
        }
        ));
    }

    [TestMethod]
    public void TestMethod2()
    {
        TryTest(new Action(() =>
        {
            DoAnotherSomething();
        }
        ));
    }

一定要重新抛出异常,这样测试才会失败。注意接球。

虽然像 Kip 的回答一样将测试代码包装在 lambda 中是一种简单且(线程)安全的替代方法,但我发现它使堆栈跟踪更难阅读,因为您将始终拥有匿名labmda 卡在那里。此外,它需要另一个嵌套级别,这让我的强迫症神经有点发痒。

我希望它可以在 MSTest 中扩展,并且在 XUnit 或 NUnit 之类的东西中你可以解决这个问题。您甚至可以通过使用类似 PostSharp 的方法在 运行 的每个方法周围叠加一个包装方法来实现这种面向方面的方法(参见 here)。

如果您出于某种原因(我们自己有一些,"attaching" 文件,已设置 CI 脚本等)无法使用 MSTest,您可以这样做。

利用 FirstChanceException 捕获任何抛出的异常。现在,我在这里提出的建议不是线程安全的并且有点古怪,但是如果您像我们一样,运行宁单线程测试并且更关心易用性而不是性能等它可能对您有用,您可以改进这通过将注册等与测试上下文捆绑在一起。

基本上,无论如何我所做的是进行全局测试 class 挂钩 FirstChanceExceptions 和 'safekeeps' 最后抛出的异常,然后我在清理方法中引用它。

[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; }
}

然后在包含清理任何测试的逻辑的基础 class 中:

[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}\r\n{e.StackTrace}");
    }
}

最近我遇到了同样的问题。而且我发现,如果您使用的是 MSTest V2,则可以轻松地扩展 TestMethod 属性 class 并使用它来代替:

public class LoggedTestMethodAttribute : TestMethodAttribute
{
   public override TestResult[] Execute(ITestMethod testMethod)
   {
      var results = base.Execute(testMethod);
      //you can loop through results and call
      //WriteExceptionLogWithScreenshot(e);
   }
}

我想当您不使用 DataRow 属性时,数组中将始终只有一个结果。 然后您可以直接从 result 项的 属性 TestFailureException

中获取异常

之后你只需要用 [LoggedTestMethod] 属性而不是 [TestMethod]

来装饰你的测试方法