如何在 ScalaTest 中显示自定义失败消息?

有人知道如何在 ScalaTest 中显示自定义失败消息吗?

例如:

NumberOfElements() should equal (5)

Shows the following message when it fails:

10不等于5

但我想要更多描述性的信息,比如:

NumberOfElements 应该是5。

15870 次浏览

You're the first to ask for such a feature. One way to achieve this is with withClue. Something like:

withClue("NumberOfElements: ") { NumberOfElements() should be (5) }

That should get you this error message:

NumberOfElements: 10 was not equal to 5

If you want to control the message completely you can write a custom matcher. Or you could use an assertion, like this:

assert(NumberOfElements() == 5, "NumberOfElements should be 5")

Can you elaborate on what your use case is? Why is it that 10 did not equal 5 is not up to snuff, and how often have you had this need?

Here's the kind of thing you're requesting:

scala> import org.scalatest.matchers.ShouldMatchers._
import org.scalatest.matchers.ShouldMatchers._


scala> withClue ("Hi:") { 1 + 1 should equal (3) }
org.scalatest.TestFailedException: Hi: 2 did not equal 3
at org.scalatest.matchers.Matchers$class.newTestFailedException(Matchers.scala:150)
at org.scalatest.matchers.ShouldMatchers$.newTestFailedException(ShouldMatchers.scala:2331)




scala> class AssertionHolder(f: => Any) {
|   def withMessage(s: String) {
|     withClue(s) { f }
|   }
| }
defined class AssertionHolder


scala> implicit def convertAssertion(f: => Any) = new AssertionHolder(f)
convertAssertion: (f: => Any)AssertionHolder


scala> { 1 + 1 should equal (3) } withMessage ("Ho:")
org.scalatest.TestFailedException: Ho: 2 did not equal 3
at org.scalatest.matchers.Matchers$class.newTestFailedException(Matchers.scala:150)
at org.scalatest.matchers.ShouldMatchers$.newTestFailedException(ShouldMatchers.scala:2331)

So this way you can write:

{ NumberOfElements() should be (5) } withMessage ("NumberOfElements:")

New way since 2011: Matchers and AppendedClue1 traits. Also, for collection sizes, there are some default messages.

import org.scalatest.{AppendedClues, Matchers, WordSpec}


class SomeTest extends WordSpec with Matchers with AppendedClues {


"Clues" should {
"not be appended" when {
"assertions pass" in {
"hi" should equal ("hi") withClue "Greetings scala tester!"
}
}
"be appended" when {
"assertions fail"  in {
1 + 1 should equal (3) withClue ", not even for large values of 1!"
}
}
"not be needed" when {
"looking at collection sizes" in {
val list = List(1, 2, 3)
list should have size 5
}
}
}
}

Output looks like this:

SomeTest:
Clues
should not be appended
- when assertions pass
should be appended
- when assertions fail *** FAILED ***
2 did not equal 3, not even for large values of 1! (SomeTest.scala:15)
should not be needed
- when looking at collection sizes *** FAILED ***
List(1, 2, 3) had size 3 instead of expected size 5 (SomeTest.scala:21)

Note that the List size message isn't great for lists with long .toString output.

See the scaladoc for more information.


1 I'm guessing the AppendedClues trait was inspired by this question, Bill Venners of the accepted answer is the author of this trait.

You can also use withClue without importing anything or adding it to the test class:

withClue(s"Expecting distinct elements: ${elements.toList}") { elements.length shouldBe 3 }

This is imported from Assertions class: org.scalatest.Assertions#withClue