断言异常时如何知道何时在 ScalaTest Matchers 中使用 `a`、`an` 或 `the`?

How to know when to use `a`, `an` or `the` in ScalaTest Matchers when asserting exceptions?

我正在阅读 ScalaTest 文档中关于 Testing Exceptions 的部分,并查看

等示例
an [IndexOutOfBoundsException] should be thrownBy s.charAt(-1)

我测试了 a,它也有效

a [IndexOutOfBoundsException] should be thrownBy s.charAt(-1)

val thrown = the [IndexOutOfBoundsException] thrownBy s.charAt(-1)

我很困惑,几乎没有关于这些关键字的文档。 谢谢

从库源码可以看出aan完全一样:

  /**
   * This method enables the following syntax: 
   *
   * <pre class="stHighlight">
   * a [RuntimeException] should be thrownBy { ... }
   * ^
   * </pre>
   */
  def a[T: ClassTag]: ResultOfATypeInvocation[T] =
    new ResultOfATypeInvocation(classTag)

  /**
   * This method enables the following syntax: 
   *
   * <pre class="stHighlight">
   * an [Exception] should be thrownBy { ... }
   * ^
   * </pre>
   */
  def an[T : ClassTag]: ResultOfAnTypeInvocation[T] =
    new ResultOfAnTypeInvocation(classTag)

  /**
   * This method enables the following syntax: 
   *
   * <pre class="stHighlight">
   * the [FileNotFoundException] should be thrownBy { ... }
   * ^
   * </pre>
   */
  def the[T : ClassTag](implicit pos: source.Position): ResultOfTheTypeInvocation[T] =
    new ResultOfTheTypeInvocation(classTag, pos)

但是,the 允许您在需要时使用 getMessage 等方法进一步检查异常。您引用的文档中的示例:

the [ArithmeticException] thrownBy 1 / 0 should have message "/ by zero"

如果您只关心正确的异常类型,请使用 a/an。如果您需要检查异常类型及其消息,请使用 the.

由于这些匹配器的字符串表示形式(如果您关心代码中的语法),生成的每个测试失败的文本都会略有不同:

// from ResultOfATypeInvocation:
override def toString: String = "a [" + clazz.getName + "]"

// from ResultOfAnTypeInvocation:
override def toString: String = "an [" + clazz.getName + "]" 

例如。

不幸的是,scalatest docs 并没有那么详细,但大致是这样的:

当您只想断言抛出的异常类型而不是其内容(例如消息、嵌套异常等)时,您应该使用 a,但实现和行为在其他方面是相同的

当异常 class 以元音开头时,您应该使用 an - 只是因为英语拼写规则。在幕后,它们由不同的机器 (AMatcher vs. AnMatcher) 表示,但行为实际上是相同的(我观察到的唯一区别是在失败消息中使用 "a" 与 "an" )

当你想对抛出的异常类型进行断言时,你应该使用the,并且还捕获异常实例以执行额外的断言(对消息、嵌套异常等)