Unit 是 Java 社区中知名度最高的单元测试工具。它诞生于 1997 年,由 Erich Gamma 和 Kent Beck 共同开发完成。其中 Erich Gamma 是经典著作《设计模式:可复用面向对象软件的基础》一书的作者之一,并在 Eclipse 中有很大的贡献;Kent Beck 则是一位极限编程(XP)方面的专家和先驱。
麻雀虽小,五脏俱全。JUnit 设计的非常小巧,但是功能却非常强大。Martin Fowler 如此评价 JUnit:在软件开发领域,从来就没有如此少的代码起到了如此重要的作用。它大大简化了开发人员执行单元测试的难度,特别是 JUnit 4 使用 Java 5 中的注解(annotation)使测试变得更加简单。
JUnit 4 初体验
在开始体验 JUnit 4 之前,我们需要以下软件的支持:
- Eclipse:最为流行的 IDE,它全面集成了 JUnit,并从版本 3.2 开始支持 JUnit 4。当然 JUnit 并不依赖于任何 IDE。您可以从http://www.eclipse.org/ 上下载最新的 Eclipse 版本。
- Ant:基于 Java 的开源构建工具,您可以在 http://ant.apache.org/ 上得到最新的版本和丰富的文档。Eclipse 中已经集成了 Ant,但是在撰写本文时,Eclipse 使用的 Ant 版本较低(必需 1.7 或者以上版本),不能很好的支持 JUnit 4。
- JUnit:它的官方网站是 http://www.junit.org/。您可以从上面获取关于 JUnit 的最新消息。如果您和本文一样在 Eclipse 中使用 JUnit,就不必再下载了。
- 首先,建立一个项目CalculatorTest,编写一个Calculator的类,实现最基本的对int型的加减乘除四则运算。该类代码(github地址:https://github.com/shuaiyue/CalculatorTest)如下:
public class Calculator { public int add(int a, int b) { return a + b; } public int substract(int a, int b) { return a - b; } public int multiply(int a, int b) { return a * b; } public int divide(int a, int b) throws Exception { if(0 == b) { throw new Exception("除数不能为0"); } else { return a / b; } } }
- 将Junit单元测试包引入项目,操作:在该项目上点击右键→"Properties",如图:在弹出的窗口中,先选择左边栏的“Java Build Path”,在右边选择“Libraries”标签,点击“Add Libraries”,点击“JUnit”引入JUnit4单元测试包。
- 生成JUnit测试框架:右击需要测试的类Calculator.java,选择“New”→“Junit Test Case”,如图:点击“Next”,在列出的待测类里选择需要测试的类,如图:之后,在生成的CalculatorTest新类,包含一些空的测试用例。手动将这些类修改完成即可。完整的CalculatorTest.java的代码如下:
import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; public class CalculateTest { private static Calculator cal = new Calculator(); @Before public void setUp() throws Exception { } @Test public void testAdd() { assertEquals(5, cal.add(2, 3)); } @Test public void testSubstract() { assertEquals(5, cal.substract(5, 0)); } @Test public void testMultiply() { assertEquals(-1, cal.multiply(-1, 1)); } @Test public void testDivide() throws Exception { cal.divide(4, 0); } }
- 运行测试代码:右击CalculatorTest类→“Run as”→“JUnit Test”运行测试用例,如图:运行结果如下:其中,进度条为红色表示发现错误,具体测试结果在进度条上显示。
各种注解的说明:
@Test:
表明该方法是一个测试方法
@BeforeClass 和 @AfterClass:
测试用例初始化时执行 @BeforeClass方法,当所有测试执行完毕之后,执行@AfterClass进行收尾工作。标注、@BeforeClass 和 @AfterClass的方法必须是static的,因为方法将在类被装载的时候就被调用,那时候还没创建测试对象实例。
@Before:
使用了该元数据的方法在每个测试方法执行之前都要执行一次。
@After:
使用了该元数据的方法在每个测试方法执行之后要执行一次。
@Test(expected=*.class) :
通过@Test元数据中的expected属性验证是否抛出期望的异常,expected属性的值是一个异常的类型,如果抛出了期望的异常,则测试通过,否则不通过。
@Test(timeout=xxx):
该元数据传入了一个时间(毫秒)给测试方法,如果测试方法在制定的时间之内没有运行完,则测试也失败。
@Ignore:
该元数据标记的测试方法在测试中会被忽略。同时可以为该标签传递一个String的参数,来表明为什么会忽略这个测试方法。比如:@lgnore("该方法还没有实现"),在执行的时候,仅会报告该方法没有实现,而不会运行测试方法。
在test方法内除了使用Assert的assertEquals()方法外,还能使用assertFalse()、assertTrue()、assertNull()、assertNotNull()、assertSame()、assertNotSame()等断言函数。而且如果使用的是Junit4,结合Hamcrest,使用
assertThat([value], [matcher statement])方法可以实现更灵活的断言判断(前提是引入hamcrest的jar包)。
例如:
// is匹配符表明如果前面待测的object等于后面给出的object,则测试通过
assertThat( testedObj, is( object) );
// containsString匹配符表明如果测试的字符串包含指定的子字符串则测试通过
assertThat( testedString, containsString( "developerWorks" ) );
// greaterThan匹配符表明如果所测试的数值testedNumber大于16.0则测试通过
assertThat( testedNumber, greaterThan(16.0) );
// closeTo匹配符表明如果所测试的浮点型数testedDouble在20.0±0.5范围之内则测试通过
assertThat( testedDouble, closeTo( 20.0, 0.5 ) );
//hasItem匹配符表明被测的迭代对象含有元素element项则测试通过assertThat(iterableObject, hasItem (element));
(注:参考博客:http://blog.csdn.net/andycpp/article/details/1327147 以及 http://www.ibm.com/developerworks/cn/java/j-lo-junit4/ )