为什么是JUnit

我们相信书中的代码示例应该都是高质量的。典型的“hello world”例子经常帮助读者测试他们的环境。我们使用独特的方法来使用书中的代码示例。大部分示例是实际的JUnit测试用例(http://www.junit.org)。JUnit,是Java单元测试框架,可以断言一个特殊情况是否能以可重复的方式出现。通过IDE或Ant进行自动JUnit测试用例可以一步一步地构筑系统。我们在本书用使用JUnit是因为平时都在其它项目中使用,并想让你看看我们如何编码。测试驱动开发(Test Driven Development, TDD)是我们强烈推荐的开发模式。

如果你对JUnit不熟,请阅读以下基础。我们也建议你阅读Dave Thomas和Andy Hunt编著的《Pragmatic Unit Testing in Java with JUnit》,还有Vincent Massol和Ted Husted编著的《JUnit in Action》。
JUnit基础

这部分是对JUnit快速但当然不完整的介绍。我们将提供理解我们示例代码所需的基础知识。首先,我们的JUnit测试用例继承junit.framework.TestCase并且很多通过部LiaTestCase基类间接继承它。我们的具体测试类附合这个命名习惯:给类名加后缀Test。例如,我们的QueryParser的测试是QueryParserTest.java。

JUnit自动执行所有类似public void testXXX()的方法,此处XXX是个任意有意义的名称。JUnit测试方法必须简洁,保持好的设计(例如创建可重复的功能模块等等)。
断言

JUnit建立在一组assert语句上,使你自由编写简洁的测试代码并使JUnit框架处理失败状态及指出细节。最常用的assert语句是assertEquals;一些是为不同的数据类型而重载的assertEquals方法。一个示例测试方法如下:public void testExample() { SomeObject obj = new SomeObject(); assertEqueals(10, obj.someMethod()); }如果指定的值(在本例中的10)不等于真实值(本例中是调用obj的someMethod的返回值),assert方法抛出运行时异常。除了assertEquals,为了方便还有一些其他assert方法。我们也使用assertTrue(expression)、assertFalse(expression)和assertNull(expression)语句。这些测试分别判断这个表达式是否是true、false和null。

assert语句有个接受一个附加的String参数的重载表示。String参数都是用来汇报的,在测试失败时向开发人员指出更多信息。我们使用这个String消息参数以更好的描述。

通过以这种风格编写我们的测试用例,可以从我们构建大系统的复杂中解放出来,而且可以每次只关注更少的细节。利用合适的测试用例,我们能够增强信心和灵活性。信心来自于我们知道代码的变化如优化算法不会破坏系统的其它部分,因为出现这种情况的话,自动测试组件能让我们在它影响产品之前发现。重构是一种改变代码内部结构的艺术(或者说科学),所以它能够适应变化的需求而又不影响系统的对外接口。
在上下文中的JUnit

让我们看一下到目前为止谈论的JUnit并把它放到本书的上下文中。JUnit测试用例继承于junit.framework.TestCase,且测试方法都类似public void testXXX()形式。我们的测试用例之一如下:public class BasicSearchingTest extends LiaTestCase { public void testTerm() throws Exception { IndexSearcher searcher = new IndexSearcher(directory); Term t = new Term(“subject”, “ant”); Query query = new TermQuery(t); Hits hits = searcher.search(query); assertEquals(“JDwA”, 1, hits.length()); One hit expected for search for “ant” t = new Term(“subject”, “junit”); hits = searcher.search(new TermQuery(t)); assertEquals(2, hits.length()); Two hits expected for “junit” searcher.close(); } }当然,我们将在之后解释这个测试用例中使用的Lucene API。现在我们只关注JUnit的细节。testTerm方法中的directory变量没在此类中定义。JUnit提供一个在执行每个测试方法之前的初始化钩子;这个钩子是名为public void setUp()的方法。我们的LiaTestCase基类以这种方式实现setUp:[code]public abstract class LiaTestCase extends TestCase {
private String indexDir = System.getProperty(“index.dir”);
protected Directory directory;

protected void setUp() throws Exception {
    directory = FSDirectory.getDirectory(indexDir, false);
}

}[/code]如果testTerm中的第一个断言失败,我们会得到一个异常:junit.framework.AssertionFalsedError: JDwA expected:<1> but was:<0> at lia.searching.BasicSearchingTest. → testTerm(BasicSearchingTest.java:20)这个失败指出我们的测试数据与预期的结果不同。

Apache Lucene 指南