在这本书中包含了几百个断言语句,你已经看到了许多,现在是了解断言的一些额外信 息的时候了,我们将审视在断言失败时产生的有意义的错误信息,反映了使用这个关键字的 原因,并且显示了如何使用断言进行内联单元测试,我们也将快速的比较groovy的解决方案 和java的assert关键字及断言在单元测试中的用法。
生成失败相关信息当断言失败的时候,断言生成堆栈和信息,放置下面这些代码:[code]a = 1
assert a==2[/code]在一个名称为Failing Assert.groovy的文件中,然后通过命令:> groovy Failing-Assert.groovy来运行这个文件,运行的结果会失败,并且生成如下信息:[code]Caught: java.lang.AssertionError: Expression: (a==2). Values: a
= 1
at FailingAssert.run(FailingAssert.groovy:2)
at FailingAssert.main(FailingAssert.groovy)[/code]你已经看到了失败,断言将在它出现的代码位置处打印出失败的异常信息和断言表达式 中变量的值。
堆栈跟踪信息显示了断言失败的位置和导致错误的方法调用顺序,堆栈信息最好是从底部向上阅读:
我们是在文件Failing Assert.groovy中;
在这个文件中,一个类Failing Assert被构建,这个类包含一个main方法;
通过main方法,我们调用了Failing Assert.run方法这个方法在Failing Assert.groovy的第二行(在运行脚本的时候,main和run方法在后台构建);
在这行,断言失败。
这里有许多信息,这些信息大多数情况下足够用来定位和理解错误,但不是全部,我们来试试另外一个读取文件的例子,如果文件不存在或者不能读,那么断言失败:input = new File('no such file')
asse rt input.exists() assert input.canRead() println input.text
产生的输出信息:
Caught: java.lang.AssertionError: Expression: input.exists()
…
这里没有提供充足的信息,丢失的信息是损坏的文件名称是什么,在这里,断言中可以
包含一个跟踪信息:input = new File('no such file ')
assert input.exists() , "cannot find '$input.name '"
assert input.canRead() , "cannot read '$input.canonicalPath'" println input.text产生如下信息:
… cannot find 'no such file '. Expression: input.exists()
这正是我们需要的信息,不管怎样,这个特殊的例子也显示了断言有时不是必须使用的,因为在这个例子中我们能够容易的输出文件信息,而不是使用断言:[code]input = new File(‘no such file’)
println input.text[/code]下面的结果提供了足够的信息:FileNotFoundException: no such file (The system cannot find the filespecified)这里引申出了断言的最佳实践:
在写断言之前,先让你的代码失败,并且看看抛出的异常信息是否充足;
当写一个断言的时候,第一次先让断言失败,看看失败的信息是否充足,如果不充足,增加一些信息,然后再次让断言失败以检查信息现在是否充足;
如果你觉得需要断言来让你的代码更清晰或者保护你的代码,增加断言而不要管前面的规则;
如果你觉得需要一个信息来使你的断言的目的和意图更清晰,增加一个这样的信息,而不要管前面的规则。
在代码中内联单元测试
最后,断言的一个有争议的用法是在产品代码中增加适当的断言来进行内联单元测试,列表6.7显示了这个策略,这个策略使用正在表达式从一个URL中提取主机名称,模式(pattern)首先被构建然后在进行真实的执行之前应用一些断言,我们也实现了一个简单的方法assertHost来进行匹配分组的断言。
在没有断言和有断言的情况下阅读这个代码,价值是显然已见的,在审视例子的时候同时从断言中了解到我们的意图,传统上,这个例子应该在测试代码中或者在一个注释中,没有比这更好的了,但是经验证明注释经常过时并且读者不能真正的注意到代码是按说明工作 的。
外部测试也常常远离代码,一些测试被终止,由于项目计划的压力它们被注释,并且最终不再运行。
在代码中内联测试也许会害怕影响程序的性能,最佳答案是使用性能分析工具检查性能是否真的受到影响,在列表6.7的断言在几毫秒内运行完成并且不一般不是问题,当性能十 分重要的时候,一个可能是放内联测试代码并且仅仅在类加载之后执行一次:放在一个静态初始化块中。
