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]
来装饰你的测试方法
我有很多以这种格式编写的测试:
[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]