在MSTest中捕获异常:Assert.ThrowsException完整指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

如何在MSTest中捕获异常而不抓狂?

\n\n

您正在编写C#单元测试,突然发现:您的方法在特定情况下应该抛出异常。如何验证这一点?如果您曾搜索过“How do I use Assert to verify that an exception has been thrown with MSTest”,那么您并不孤单——这是Stack Overflow上最热门的问题之一。今天我们将一劳永逸地解决它。

\n\n

在本文中,我将向您展示MSTest中检查异常的所有方法:从经典属性到现代的Assert.ThrowsException。您将学习如何编写干净、可靠的测试,这些测试不会在最不合时宜的时刻失败。我们开始吧!

\n\n

为什么检查异常很重要?

\n\n

想象一下:您有一个方法Divide(int a, int b)。如果b = 0,它应该抛出DivideByZeroException。如果没有测试,只有当应用程序在生产环境中崩溃时您才会知道。带有异常检查的单元测试就是您的安全绳。

\n\n

在MSTest(微软的单元测试框架)中,有几种方法。我们将逐一介绍,但首先从最现代且推荐的方法开始。

\n\n

方法1:Assert.ThrowsException(最正确的方法)

\n\n

从MSTest V2(2.x版本)开始,我们有了内置方法Assert.ThrowsException<T>。它优雅、可读且灵活。语法很简单:

\n\n
[TestMethod]\npublic void Divide_ByZero_ThrowsDivideByZeroException()\n{\n    // Arrange\n    var calculator = new Calculator();\n\n    // Act & Assert\n    Assert.ThrowsException<DivideByZeroException>(() => calculator.Divide(10, 0));\n}
\n\n

这里发生了什么?我们传递一个包含方法调用的lambda表达式。MSTest在try-catch块内执行它。如果没有抛出异常——测试失败。如果抛出了其他类型的异常——同样失败。只有预期的异常才会导致成功。

\n\n

高级示例:检查异常消息

\n\n

有时不仅需要确认异常的类型,还需要确认其消息。为此,请使用带有message参数的重载,或检查异常对象的属性:

\n\n
[TestMethod]\npublic void GetUserById_InvalidId_ThrowsWithCorrectMessage()\n{\n    // Arrange\n    var service = new UserService();\n\n    // Act\n    var exception = Assert.ThrowsException<ArgumentException>(() => service.GetUserById(-1));\n\n    // Assert额外检查\n    Assert.AreEqual("Id must be positive", exception.Message);\n}
\n\n

请注意:Assert.ThrowsException会返回异常对象!这使您可以检查它的任何属性:InnerException、Data、StackTrace(尽管通常不检查最后一个)。

\n\n

方法2:[ExpectedException]属性(已过时,但仍在使用)

\n\n

以前(在MSTest V1中),在测试方法本身上使用属性。看起来像这样:

\n\n
[TestMethod]\n[ExpectedException(typeof(DivideByZeroException))]\npublic void Divide_ByZero_ThrowsDivideByZeroException_OldWay()\n{\n    var calculator = new Calculator();\n    calculator.Divide(10, 0);\n}
\n\n

看起来方便?但存在三个问题:

\n
    \n
  • 无法检查异常消息。您不知道抛出的异常是否正确。
  • \n
  • 任何此类型的异常都算成功。即使它来自代码的其他行(例如,在Arrange中)。
  • \n
  • 无法在异常后执行代码。测试方法会立即中断。
  • \n
\n\n

因此,在新项目中使用Assert.ThrowsException。[ExpectedException]属性已被标记为deprecated(已过时),可能会在将来版本中被移除。

\n\n

方法3:手动try-catch(适合极限玩家)

\n\n

有时(非常罕见)您需要

博客

书籍推荐