如何优化ScalaTest参数化测试失败时的对象描述信息?
我之前在ScalaTest里用数组做参数化测试时,也碰到过这种数组显示成[I@xxx哈希值的糟心事,完全看不出数组里实际是什么元素,排查错误特别费劲!咱们来解决这个可读性问题,顺便帮你更快定位数组越界的根源。
核心问题原因
Scala里的数组(比如Array[Int])默认的toString方法就是输出这种类名加哈希码的格式,ScalaTest在报错时直接用了这个默认输出,导致我们看不到数组里的实际元素。另外报错里提到的行号(零基的行2),如果没有测试用例描述,也很难快速对应到具体的测试场景。
解决办法,按易用程度排序:
1. 给断言加上自定义提示(最快见效)
在你的断言语句后面加上withClue,把数组转换成可读的字符串形式。这样一旦断言失败,报错信息里就会显示数组的实际元素了:
sortArray(input) should equal(expected) withClue s" | Input: ${input.mkString("[", ", ", "]")}, Expected: ${expected.mkString("[", ", ", "]")}"
比如原来的报错会变成类似:
ArrayIndexOutOfBoundsException was thrown during property evaluation. (SortingSpec.scala:43)
Message: 2
Occurred at table row 2 (zero based, not counting headings), which had values ( Input = [2, 1], Expected = [1, 2] )
| Input: [2, 1], Expected: [1, 2]
一下子就能看清楚出错的数组内容了。
2. 给测试用例添加描述字段
在你定义的Table里加一个描述列,这样报错时能直接知道是哪个测试场景出了问题,不用对着行号猜:
val testCases = Table( ("Test Scenario", "Input", "Expected"), ("Odd-length unsorted array", Array(1,3,2), Array(1,2,3)), ("Reverse-sorted array", Array(5,4,3,2,1), Array(1,2,3,4,5)), ("2-element even array", Array(2,1), Array(1,2)) // 这就是报错里的行2 )
之后报错会显示对应的场景名称,比如:
Occurred at table row 2 (zero based, not counting headings), which had values ( Test Scenario = 2-element even array, Input = [I@17c386de, Expected = [I@5af97850 )
结合上面的withClue,就能完美定位问题了。
3. 用List替代Array(最省心)
如果你的测试逻辑允许,直接把测试数据换成List就行——Scala的List默认toString就是显示元素的(比如List(2,1)),不用做任何额外处理,报错信息里直接就能看到数组内容:
val testCases = Table( ("Test Scenario", "Input", "Expected"), ("Odd-length unsorted array", List(1,3,2), List(1,2,3)), ("Reverse-sorted array", List(5,4,3,2,1), List(1,2,3,4,5)), ("2-element even array", List(2,1), List(1,2)) )
4. 自定义数组的toString(适合复杂场景)
如果必须用Array,你可以给数组包装一个简单的类,重写toString方法,或者在定义测试数据时就把数组转换成可读字符串(不过后者会丢失数组类型,需要在测试里再转回来,不太推荐):
// 自定义包装类 case class PrintableArray[T](arr: Array[T]) { override def toString: String = arr.mkString("[", ", ", "]") } // 测试用例里用包装类 val testCases = Table( ("Input", "Expected"), (PrintableArray(Array(1,3,2)), PrintableArray(Array(1,2,3))), // ...其他用例 )
额外调试技巧
针对你碰到的ArrayIndexOutOfBoundsException,现在能看到数组实际元素后,先检查出错行的输入数组长度,看看你的排序逻辑里是不是有索引操作没处理好边界(比如数组长度是2,代码里却访问了索引2)。比如如果你的排序函数里写了类似arr(i+2)的操作,当数组长度不足时就会触发这个异常。
内容的提问来源于stack exchange,提问作者devoured elysium




