JUnit 4是JUnit框架有史以来的最大改进,其主要目标便是利用Java 5的Annotation特性简化测试用例的编写。让我们看看如何使用JUnit 4来进行Unit测试。
请注意:本文主要介绍JUnit 4的最新特性和用法,并不会讲解Unit测试的基础。如果你对JUnit框架还不熟悉,请先参考“Eclipse快速上手指南 (2) 使用JUnit测试”一文,学习如何编写JUnit测试。
我们使用的开发环境是Eclipse 3.2,它已经自带了JUnit 4.1,你需要将JUnit 4 Library添加到项目用到的Library中。另外,必须使用JDK 5.0或更高版本。
要在Eclipse环境之外运行JUnit,需要下载JUnit 4.1,具体请访问JUnit.org。
我们先看一个简单的Math类:
package com.javaeedev.junit4;
public class Math {
public int abs(int value) {
return value>=0 ? value : (-value);
}
public int div(int a, int b) {
return a / b;
}
/**
* BUG: if b less than 0!
*/
public float exp(int a, int b) {
float r = 1;
for(int i=0; i<b; i++)
r = r * a;
return r;
}
}
注意exp()方法是有Bug的,如果传入参数2, -1,则期待的返回值应为0.5F,但实际返回值为1.0F。
下面我们看看传统的JUnit的TestCase:
public class MathTest extends TestCase {
public void setUp() { super.setUp(); }
public void tearDown() { super.tearDown(); }
public void testAbs() { assertTrue(true); }
public void testDiv() {...}
public void testExp() {...}
}
JUnit依赖反射来执行每个以test开头的方法。然而,在最新的JUnit 4中,由于有了Annotation的支持,我们的测试方法不需要再以testXxx标识了,而是写上一个@Test标注即可。例如:
@Test public void doAbs() {...}
甚至MathTest类也不必继承自TestCase。你也许会想到,不继承自TestCase就无法调用assertXxx方法了,正因为如此,所有的assertXxx方法全部以静态方法被放入了Assert类,使用Assert.assertXxx()调用。如果使用
import static org.junit.Assert.*;
则原有的代码不必改动。
setUp()和tearDown()方法也依赖@Before和@After标记,这样做的最大的好处是在继承体系内不必担心忘记了在setUp()方法中调用父类的super.setUp()方法,JUnit框架会自动处理父类的@Before和@After标记的方法。
并且,JUnit框架对@Before和@After的调用顺序类似于类的构造方法和析构方法,即@Before按照父类到子类的顺序调用,@After则相反,这样保证了资源的正确获取和释放。
当然,不再强迫必须使用setUp和tearDown作为方法名,可以使用更有意义的方法名,例如:initDatabase()和closeDatabase(),只要它们被标注了@Before和@After即可。
来看看使用Annotation的MathTest:
package com.javaeedev.junit4;
import static org.junit.Assert.*;
import org.junit.*;
public class MathTest {
public MathTest() {
System.out.println("new MathTest instance.");
}
@Before
public void setUp() throws Exception {
System.out.println("call @Before before a test method");
}
@After
public void tearDown() throws Exception {
System.out.println("call @After after a test method");
}
@Test
public void doAbs() {
Math math = new Math();
assertEquals(200, math.abs(200));
assertEquals(100, math.abs(-100));
assertEquals(0, math.abs(0));
}
@Test
public void doDiv() {
Math math = new Math();
assertEquals(5, math.div(100, 20));
assertEquals(4, math.div(100, 21));
}
@Test(expected=ArithmeticException.class)
public void doDiv0() {
new Math().div(127, 0);
}
@Test(timeout=1)
public void doLongTimeTask() {
double d = 0;
for(int i=1; i<10000000; i++)
d+=i;
}
@Test
public void testExp() {
Math math = new Math();
assertEquals(32f, math.exp(2, 5), 0.001f);
assertEquals(1f, math.exp(2, 0), 0.001f);
assertEquals(0.5f, math.exp(2, (-1)), 0.001f);
}
}
对测试异常,JUnit 4可以用expected=Exception.class来期待一个预期的异常,而不必编写
try {
...
fail("No exception");
}
catch(Exception e) {
// OK!
}
来看看doDiv0测试,我们期待一个除数为0的ArithmeticException,因此编写如下测试方法:
@Test(expected=ArithmeticException.class)
public void doDiv0() {
new Math().div(127, 0);
}
对于非常耗时的测试,@Test还有一个timeout来标识该方法最长执行时间,超过此时间即表示该测试方法失败:
@Test(timeout=1)
public void doLongTimeTask() {
double d = 0;
for(int i=1; i<10000000; i++)
d+=i;
}
以上方法若执行时间超过1ms则测试失败,由于依赖CPU的执行速度,在不同的机器上测试结果也不同。
JUnit 4另一个较大的变化是引入了@BeforeClass和@AfterClass,它们在一个Test类的所有测试方法执行前后各执行一次。这是为了能在@BeforeClass中初始化一些昂贵的资源,例如数据库连接,然后执行所有的测试方法,最后在@AfterClass中释放资源。
正如你能想到的,由于@BeforeClass和@AfterClass仅执行一次,因此它们只能标记静态方法,在所有测试方法中共享的资源也必须是静态引用:
private static Object dbConnection;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println("call @BeforeClass and init database connection");
dbConnection = new Object();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println("call @AfterClass to release database connection");
dbConnection = null;
}
最后执行测试用例,可以看到结果:
各个方法执行顺序如下:
call @BeforeClass and init database connection
new MathTest instance.
call @Before before a test method
call @After after a test method
new MathTest instance.
call @Before before a test method
call @After after a test method
...
call @AfterClass to release database connection
可以看到,@BeforeClass是在实例化MathTest之前调用的,因此不能在构造方法中初始化共享资源。
最后需要注意的是由于Java 5的自动Box/Unbox特性,在调用assertEquals()时要特别注意,如果你传入:
assertEquals(100F, 100);
则按照自动Box变为:
assertEquals(new Float(100F), new Integer(100));
测试失败,因为Float类和Integer类不是同一类型。
因此要特别注意float和double的测试。事实上对float和double应使用
assertEquals(float, float, float delta);
assertEquals(double, double, double delta);
delta指定了两个作比较的浮点数的相差范围,在此范围内的两个浮点数将认为相等。可以传入一个很小的数例如0.0001F。
JUnit 4非常适合使用Java 5的开发人员,但是无法在Java 1.4中获得这些好处,并且,也不与以前的版本兼容。因此,如果你正在使用Java 5,就可以考虑使用JUnit 4来编写测试。
分享到:
相关推荐
junit4 快速入门 比较简单易学,欢迎前来学习
针对Calculate类 (含加减乘除4个方法),使用junit4进行简单的单元测试例子,含注释~
很简单的说明,这是好的一个开始,希望大家能够看到,学习测试是很重要的。
此文件包含源代码(简单加减乘除),测试源码(junit4框架下的单元测试源码),入门级学习材料。Eclipse开发环境下
以一个简单的DEMO介绍如何在Eclipse下使用JUnit4。供初次接触JUnit的同学学习
junit的简单介绍
JUnit+Ant+Jacoco整合 一个小Demo源码,亲测通过,可以作为入门资源。
意志测试 不要编辑此文件。 请参阅说明。 概述 Willtest 通过提供一组和其他实用程序类使 JUnit...入门 代码由几个小的构建块组成。 开始编写浏览器测试只需要core模块。 尽管如此, misc模块将通过一些辅助类和一个可
编程简介(Java + JUnit版)为什么要学习编程? “与机器竞争”( )我们...增加产量铁定律“一次做一件事”进球,清除并继续前进小目标=测试测试驱动开发(TDD) 使用Junit进行Java测试入门如何进行练习在Github上分叉
<groupId>junit <artifactId>junit <version>4.6 <scope>test <!-- https://mvnrepository.com/artifact/io.netty/netty-all --> <groupId>io.netty <artifactId>netty-all <version>4.1.50.Final ...
可以和 Junit5 完美契合。使用简单,便于项目开发过程中的测试实用。提供拓展,用户可进行自定义开发。特性支持 I18N支持多种报告生成方式,支持自定义Junt5 完美支持,便于 Java 开发者使用变更记录v2.0.7 主要变更...
本书最大的特色在于每章都是由浅入深,从一个简单的示例入手,让读者快速了解本章内容,然后再详细讲解本章涉及的基本原理和知识点,最后再通过一个详细的示例宋巩固所学内容。 本书每一章的例子都是经过精挑细选,...
hibernate入门小示例,平台环境 myeclipse + oracle, 使用junit对hibernate的简单增删改查进行验证,并实现日志记录。
spring初学入门demo,包含一个简单的测试类,junit 依赖的包,配置文件,详情可以参考博客文章
Android 单元测试入门Start简单了解一下,如何依赖 Junit 进行 Java 代码的单元测试。依旧如何借助 Robolectric 进行 Andro
本书最大的特色在于每章都是由浅入深,从一个简单的示例入手,让读者快速了解本章内容,然后再详细讲解本章涉及的基本原理和知识点,最后再通过一个详细的示例宋巩固所学内容。 本书每一章的例子都是经过精挑细选,...
创建一个简单项目,集成JUNIT单元测试,编写视图显示,创建自定义标签...
基于elasticsearch和Junit单元测试方法对index、search、get、delete的简单操作。 第一步:启动一个elasticsearch服务,bin目录下的elasticsearch.bat 第二步:建索引,执行_Index中单元测试方法index() 第三步:检索,...
2.13.1 简单比较....... 66 2.13.2 了解比较....... 67 2.13.3 使用比较....... 69 2.14 历史纪录............. 71 2.15 回应 UI.............. 73 3.喜好设定(Preferences) ...... 76 3.1 工作台(Workbench)....
SharedPreferences存储对于简单的键值对形式非常方便快捷,同时文档中介绍了如何实现两个应用程序共享某个文件?对于开发公司系列应用,同时各应用需要交叉访问数据,这一点非常有用。 4、Android权限控制 Android...