- 浏览: 413305 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (101)
- 数据库 (4)
- 上网吧 (1)
- Mysql (3)
- flex (4)
- flex相关 (4)
- java (15)
- eclipse (3)
- 笔试题 (2)
- 面试题 (1)
- 软件开发问题 (1)
- 个性化 推荐 移动网络 智能手机 (1)
- Spring (2)
- struts2 (2)
- Cookie (1)
- cookie中文乱码 (1)
- cooke.setPath (1)
- cookie.setDomain (1)
- ibatis (1)
- update (1)
- Map (2)
- HashMap (1)
- List (1)
- ArrayList (1)
- 手机号码 (1)
- 归属地 (1)
- 接口 (1)
- HttpClient (1)
- web service (1)
- 服务与接口 (1)
- equals (1)
- 空指针异常 (1)
- java 异常 Syntax error 诡异 (1)
- StringUtils (1)
- 数据库 锁 悲观锁 乐观锁 (1)
- TreeMap LinkedHashMap (1)
- java 排序算法 (1)
- java MAP (1)
- ftp (1)
- ftpsClient (1)
- ftps (1)
- DateTime (2)
- Calendar (1)
- Date (2)
最新评论
-
wygdove:
楼主好,有一个问题请教。对于第二段示例代码,楼主说到“如果字符 ...
关于java中split的使用 -
无痕海:
可以选择用迭代器来删除。
Arrays.asList() 返回的list不能add,remove -
u012076104:
顶
关于java中split的使用 -
hanmiao:
代码那叫壹個乱,就不能用下高亮工具嘛...
JUnit使用方法 -
shinestarwang:
严重误导别人!,你是不知道什么是空白符呢还是写错了呢?你把/s ...
关于java中split的使用
JUnit是一个开源的Java单元测试框架。
1.为什么要使用JUnit
以前,开发人员写一个方法,如下代码所示:
//******* AddAndSub.java**************
public Class AddAndSub {
public static int add(int m, int n) {
int num = m + n;
return num;
}
public static int sub(int m, int n) {
int num = m - n;
return num;
}
}
如果要对AddAndSub类的add和sub方法进行测试,通常要在main里编写相应的测试方法,如下代码所示:
//******* MathComputer.java**************
public Class AddAndSub {
public static int add(int m, int n) {
int num = m + n;
return num;
}
public static int sub(int m, int n) {
int num = m - n;
return num;
}
public static void main(String args[]) {
if (add (4, 6) == 10)) {
System.out.println(“Test Ok”);
} else {
System.out.println(“Test Fail”);
}
if (sub (6, 4) ==2)) {
System.out.println(“Test Ok”);
} else {
System.out.println(“Test Fail”);
}
}
}
从上面的测试可以看出,业务代码和测试代码放在一起,对于复杂的业务逻辑,一方面代码量会非常庞大,另一方面测试代码会显得比较凌乱,而JUnit就能改变这样的状况,它提供了更好的方法来进行单元测试。使用JUnit来测试前面代码的示例如下:
//******* TestAddAndSub.java**************
import junit.framework.TestCase;
public Class TestAddAndSub extends TestCase {
public void testadd() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(4, 6));
}
public void testsub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(6, 4));
}
public static void main(String args[]){
junit.textui.TestRunner.run(TestAddAndSub .class); }
}
这里先不对JUnit的使用方法进行讲解,从上可以看到,测试代码和业务代码分离开,使得代码比较清晰,如果将JUnit放在Eclipse中,测试起来将会更加方便。
2 建立JUnit的开发环境
2.1 下载JUnit
从www.junit.org可以进入到JUnit的首页。
本书使用的版本是4.3版本,单击“Junit4.3.zip”即可进入下载JUnit的画面。
下载Junit4.3.zip,下载后解压缩即可。
2.2 配置JUnit
下载Junit4.3.zip完毕,并解压缩到D盘根目录下后,即可开始配置环境变量。用前面介绍的设定系统变量的方法,设定ClassPath,ClassPath=***;D:\junit\junit.jar,如图8.3所示。
查看是否配置好JUnit,在类里添加如下语句:
import junit.framework.TestCase;
图8.3 设定系统变量ClassPath
如果编译没有错误,则说明配置成功。
3 JUnit的使用方法
JUnit的使用非常简单,共有3步:第一步、编写测试类,使其继承TestCase;第二步、编写测试方法,使用test+×××的方式来命名测试方法;第三步、编写断言。如果测试方法有公用的变量等需要初始化和销毁,则可以使用setUp,tearDown方法。
3.1 继承TestCase
如果要使用JUnit,则测试类都必须继承TestCase。当然目前的最新版JUnit是不需要继承它的,但并不是说TestCase类就没有用了,它仍然是JUnit工作的基础。这里先讲述继承TestCase类的方式,稍后再介绍不继承的方式。
下面是前面使用JUnit进行测试AddAndSub类的代码,这里进行详细的分析:
//******* TestAddAndSub.java**************
import junit.framework.TestCase;
public Class TestAddAndSub extends TestCase {
public void testadd() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(4, 6));
}
public void testsub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(6, 4));
}
public static void main(String args[]){
junit.textui.TestRunner.run(TestAddAndSub .class); }
}
代码说明:
— 这里继承TestCase,表示该类是一个测试类。
— 然后使用junit.textui.TestRunner.run方法来执行这个测试类。
这里给出TestCase的源代码:
//******* TestCase.java**************
package junit.framework;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public abstract class TestCase extends Assert implements Test {
/**测试案例的名称*/
private String fName;
/**构造函数
*/
public TestCase() {
fName= null;
}
/**带参数的构造函数
*/
public TestCase(String name) {
fName= name;
}
/**获取被run执行的测试案例的数量
*/
public int countTestCases() {
return 1;
}
/**创建一个TestResult
* @see TestResult
*/
protected TestResult createResult() {
return new TestResult();
}
/**执行run方法,返回TestResult
* @see TestResult
*/
public TestResult run() {
TestResult result= createResult();
圆角矩形: 下面一段代码描述了JUnit如何实现在执行具体的测试方法前,先执行初始化方法,在执行完具体的测试方法后,再执行销毁方法. run(result);
return result;
}
/**执行run方法,参数为TestResult
*/
public void run(TestResult result) {
result.run(this);
}
/**执行测试方法,包括初始化和销毁方法
* @throws Throwable if any exception is thrown
*/
public void runBare() throws Throwable {
Throwable exception= null;
setUp();
try {
runTest();
} catch (Throwable running) {
exception= running;
}
finally {
try {
tearDown();
} catch (Throwable tearingDown) {
if (exception == null) exception= tearingDown;
}
}
if (exception != null) throw exception;
}
/**执行测试方法
* @throws Throwable if any exception is thrown
*/
protected void runTest() throws Throwable {
assertNotNull("TestCase.fName cannot be null", fName); // Some VMs crash when calling getMethod(null,null);
Method runMethod= null;
try {
//利用反射机制
runMethod= getClass().getMethod(fName, (Class[])null);
} catch (NoSuchMethodException e) {
fail("Method \""+fName+"\" not found");
}
if (!Modifier.isPublic(runMethod.getModifiers())) {
fail("Method \""+fName+"\" should be public");
}
//利用反射机制
try {
runMethod.invoke(this);
}
catch (InvocationTargetException e) {
e.fillInStackTrace();
throw e.getTargetException();
圆角矩形: 下面一段代码定义了要想实现初始化和销毁方法,需继承这两个方法. }
catch (IllegalAccessException e) {
e.fillInStackTrace();
throw e;
}
}
/**测试前的初始化方法
*/
protected void setUp() throws Exception {
}
/**测试后的销毁方法
*/
protected void tearDown() throws Exception {
}
/**返回测试案例的名称
* @return the name of the TestCase
*/
public String getName() {
return fName;
}
/**设定测试案例的名称
* @param name the name to set
*/
public void setName(String name) {
fName= name;
}
}
代码说明:
— 该类继承了Assert 类,实现了Test接口。
— 可以看出,TestCase类正是通过runBare实现了在测试方法前初始化相关变量和环境,在测试方法后销毁相关变量和环境
3.2 编写测试方法
测试方法名要以test+方法名来命名,当然最新版的JUnit支持直接以方法名来命名测试方法。这是通过TestCase类里的runTest方法来实现的,主要利用了Java的反射机制,runTest方法的代码如下:
protected void runTest() throws Throwable {
assertNotNull("TestCase.fName cannot be null", fName); // Some VMs crash when calling getMethod(null,null);
Method runMethod= null;
try {
// 获取要测试的方法
runMethod= getClass().getMethod(fName, (Class[])null);
} catch (NoSuchMethodException e) {
fail("Method \""+fName+"\" not found");
}
//判断要测试的方法是否为公用方法
if (!Modifier.isPublic(runMethod.getModifiers())) {
fail("Method \""+fName+"\" should be public");
}
//Java的反射机制
try {
runMethod.invoke(this);
}
//抛出调用异常
catch (InvocationTargetException e) {
e.fillInStackTrace();
throw e.getTargetException();
}
catch (IllegalAccessException e) {
e.fillInStackTrace();
throw e;
}
}
3.3 编写断言
JUnit主要有以下断言:
— assertEquals(期望值,实际值),检查两个值是否相等。
— assertEquals(期望对象,实际对象),检查两个对象是否相等,利用对象的equals()方法进行判断。
— assertSame(期望对象,实际对象),检查具有相同内存地址的两个对象是否相等,利用内存地址进行判断,注意和上面assertEquals方法的区别。
— assertNotSame(期望对象,实际对象),检查两个对象是否不相等。
— assertNull(对象1,对象2),检查一个对象是否为空。
— assertNotNull(对象1,对象2),检查一个对象是否不为空。
— assertTrue(布尔条件),检查布尔条件是否为真。
— assertFalse(布尔条件),检查布尔条件是否为假。
这些断言主要定义在JUnit的Assert类里,Assert类的示例代码如下:
//******* Assert.java**************
package junit.framework;
/**一系列的断言方法
*/
public class Assert {
/**构造函数
*/
protected Assert() {
}
/**断言是否为真,带消息
*/
static public void assertTrue(String message, boolean condition) {
if (!condition)
fail(message);
}
/**断言是否为真
*/
static public void assertTrue(boolean condition) {
assertTrue(null, condition);
}
/**断言是否为假,带消息
*/
static public void assertFalse(String message, boolean condition) {
assertTrue(message, !condition);
}
/**断言是否为假
*/
static public void assertFalse(boolean condition) {
assertFalse(null, condition);
}
圆角矩形: 下面一段代码描述了如何在JUnit中实现判断是否相等的方法,这些方法要实现的内容相同,只是参数不同,从而实现了可以针对不同类型的数据来判断是否相等的功能. /**断言是否为失败
*/
static public void fail(String message) {
throw new AssertionFailedError(message);
}
/**断言是否为失败
*/
static public void fail() {
fail(null);
}
/**是否相等的断言,带消息Object
*/
static public void assertEquals(String message, Object expected, Object actual) {
if (expected == null && actual == null)
return;
if (expected != null && expected.equals(actual))
return;
failNotEquals(message, expected, actual);
}
/**是否相等的断言,Object
*/
static public void assertEquals(Object expected, Object actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息String
*/
static public void assertEquals(String message, String expected, String actual) {
if (expected == null && actual == null)
return;
if (expected != null && expected.equals(actual))
return;
throw new ComparisonFailure(message, expected, actual);
}
/**是否相等的断言,String
*/
static public void assertEquals(String expected, String actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息double
*/
static public void assertEquals(String message, double expected, double actual, double delta) {
if (Double.compare(expected, actual) == 0)
return;
if (!(Math.abs(expected-actual) <= delta))
failNotEquals(message, new Double(expected), new Double(actual));
}
/**是否相等的断言,double
*/
static public void assertEquals(double expected, double actual, double delta) {
assertEquals(null, expected, actual, delta);
}
/**是否相等的断言,带消息float
*/
static public void assertEquals(String message, float expected, float actual, float delta) {
if (Float.compare(expected, actual) == 0)
return;
if (!(Math.abs(expected - actual) <= delta))
failNotEquals(message, new Float(expected), new Float(actual));
}
/**是否相等的断言, float
*/
static public void assertEquals(float expected, float actual, float delta) {
assertEquals(null, expected, actual, delta);
}
/**是否相等的断言,带消息long
*/
static public void assertEquals(String message, long expected, long actual) {
assertEquals(message, new Long(expected), new Long(actual));
}
/**是否相等的断言, long
*/
static public void assertEquals(long expected, long actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息boolean
*/
static public void assertEquals(String message, boolean expected, boolean actual) {
assertEquals(message, Boolean.valueOf(expected), Boolean.valueOf(actual));
}
/**是否相等的断言,boolean
*/
static public void assertEquals(boolean expected, boolean actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息byte
*/
static public void assertEquals(String message, byte expected, byte actual) {
assertEquals(message, new Byte(expected), new Byte(actual));
}
/**是否相等的断言, byte
*/
static public void assertEquals(byte expected, byte actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息char
*/
static public void assertEquals(String message, char expected, char actual) {
assertEquals(message, new Character(expected), new Character(actual));
}
/**是否相等的断言,char
*/
static public void assertEquals(char expected, char actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息short
*/
static public void assertEquals(String message, short expected, short actual) {
assertEquals(message, new Short(expected), new Short(actual));
}
/**是否相等的断言,short
static public void assertEquals(short expected, short actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息int
*/
static public void assertEquals(String message, int expected, int actual) {
assertEquals(message, new Integer(expected), new Integer(actual));
}
/**是否相等的断言,int
*/
static public void assertEquals(int expected, int actual) {
assertEquals(null, expected, actual);
}
圆角矩形: 下面一段代码描述了JUnit中如何实现判断是否为null的方法,这些方法的功能相同,只是一个带消息,一个不带消息. /**是否不为null的断言 Object
*/
static public void assertNotNull(Object object) {
assertNotNull(null, object);
}
/**是否不为null的断言,带消息Object
*/
static public void assertNotNull(String message, Object object) {
assertTrue(message, object != null);
}
/**是否为null的断言Object
*/
圆角矩形: 下面一段代码描述了JUnit中如何实现判断是否相同的方法,这些方法要实现的内容相同,只是参数不同. static public void assertNull(Object object) {
assertNull(null, object);
}
/**是否为null的断言,带消息Object
*/
static public void assertNull(String message, Object object) {
assertTrue(message, object == null);
}
/**是否相同的断言,带消息*/
static public void assertSame(String message, Object expected, Object actual) {
if (expected == actual)
return;
failNotSame(message, expected, actual);
}
/**是否相同的断言,Object
*/
static public void assertSame(Object expected, Object actual) {
assertSame(null, expected, actual);
}
/**是否不相同的断言,带消息
*/
static public void assertNotSame(String message, Object expected, Object actual) {
if (expected == actual)
failSame(message);
}
/**是否不相同的断言Object
*/
static public void assertNotSame(Object expected, Object actual) {
assertNotSame(null, expected, actual);
}
/**相同时失败
*/
static public void failSame(String message) {
String formatted= "";
if (message != null)
formatted= message+" ";
fail(formatted+"expected not same");
}
/**不相同时失败
*/
static public void failNotSame(String message, Object expected, Object actual) {
String formatted= "";
if (message != null)
formatted= message+" ";
fail(formatted+"expected same:<"+expected+"> was not:<"+actual+">");
}
/**不相等时失败
*/
static public void failNotEquals(String message, Object expected, Object actual) {
fail(format(message, expected, actual));
}
/**格式化消息
*/
public static String format(String message, Object expected, Object actual) {
String formatted= "";
if (message != null)
formatted= message+" ";
return formatted+"expected:<"+expected+"> but was:<"+actual+">";
}
}
从上述代码中,读者可以研读JUnit中有关断言的实现方式,其实,最终都是使用后面的几个static方法来实现的。
Java 5的发布为JUnit带来了新的特性。自JUnit 4.0之后,JUnit大量使用了annotations特性,使编写单元测试变得更加简单。
4.1 改变测试方法的命名方式
前面讲过,使用JUnit 4.0以上版本可以不用遵循以前JUnit约定的测试方法命名方法,以前命名方法的示例代码如下:
//******* TestAddAndSub.java**************
import junit.framework.TestCase;
public class TestAddAndSub extends TestCase {
public void testadd() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(4, 6));
}
public void testsub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(6, 4));
}
public static void main(String args[]){
junit.textui.TestRunner.run(TestAddAndSub .class); }
}
JUnit 4.0以上版本的命名方式,是在测试方法前使用@Test注释,示例代码如下:
//******* TestAddAndSub.java**************
import junit.framework.TestCase;
import org.junit.*;
public class TestAddAndSub extends TestCase {
@Test public void add() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(4, 6));
}
@Test public void sub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(6, 4));
}
}
这个时候,测试方法的命名将不再重要,开发人员可以按照自己的命名方式来命名。
4.2 不再继承TestCase
新版本的JUnit将不再强制继承TestCase,但需要import org.junit.Assert来实现断言,示例代码如下:
//******* TestAddAndSub.java**************
import static org.junit.Assert.assertEquals;
import org.junit.*;
public class TestAddAndSub{
@Test public void add() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(4, 6));
}
@Test public void sub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(6, 4));
}
}
4.3 改变初始化和销毁方式
以前,JUnit使用SetUp和TearDown方法来进行初始化和销毁动作,JUnit 4.0以上版本将不再强制使用SetUp和TearDown方法来进行初始化和销毁,原来使用SetUp和TearDown方法的示例代码如下:
//******* TestAddAndSub.java**************
import junit.framework.TestCase;
public class TestAddAndSub extends TestCase {
private int m = 0;
private int n = 0;
//初始化
protected void setUp() {
m = 4;
n = 6;
}
public void testadd() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(m, n));
}
public void testsub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(n, m));
}
//销毁
protected void tearDown() {
m = 0;
n = 0;
}
}
不使用SetUp和TearDown方法的示例代码如下:
//******* TestAddAndSub.java**************
import static org.junit.Assert.assertEquals;
import org.junit.*;
public class TestAddAndSub {
protected int m = 0;
protected int n = 0;
//初始化
@Before public void init() {
m = 4;
n = 6;
}
@Test public void add() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(m, n));
}
@Test public void sub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(n, m));
}
//销毁
@After public void destory() {
m = 0;
n = 0;
}
}
上面示例中的初始化和销毁都是针对一个方法来说的,每个方法执行前都要进行初始化,执行完毕都要进行销毁。而JUnit的最新版本则提供了新的特性,针对类进行初始化和销毁。也就是说,该类中的方法只进行一次初始化和销毁,方法就是使用@Before和@After,示例代码如下:
//******* TestAddAndSub.java**************
import static org.junit.Assert.assertEquals;
import org.junit.*;
public class TestAddAndSub {
protected int m = 0;
protected int n = 0;
//初始化
@BeforeClass public void init() {
m = 4;
n = 6;
}
@Test public void add() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(m, n));
}
@Test public void sub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(n, m));
}
//销毁
@AfterClass public void destory() {
m = 0;
n = 0;
}
}
上述初始化和销毁动作,只执行一次即可。
4.4 改变异常处理的方式
以前,使用JUnit进行单元测试时,如果遇到异常情况,需要使用try…catch的形式来捕捉异常,示例代码如下:
//******* TestAddAndSub.java**************
import junit.framework.TestCase;
public class TestAddAndSub extends TestCase {
private int m = 0;
private int n = 0;
//初始化
protected void setUp() {
m = 4;
n = 6;
}
public void testadd() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(m, n));
}
public void testsub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(n, m));
}
public void testdiv() {
//断言除数为0
try {
int n = 2 / 0;
fail("Divided by zero!");
}
catch (ArithmeticException success) {
assertNotNull(success.getMessage());
}
}
//销毁
protected void tearDown() {
m = 0;
n = 0;
}
}
JUnit4.0以后的版本将不再使用try…catch的方式来捕捉异常,示例代码如下:
//******* TestAddAndSub.java**************
import static org.junit.Assert.assertEquals;
import org.junit.*;
public class TestAddAndSub {
protected int m = 0;
protected int n = 0;
//初始化
@Before public void init() {
m = 4;
n = 6;
}
@Test public void add() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(m, n));
}
@Test public void sub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(n, m));
}
@Test t(expected=ArithmeticException.class) public void div() {
//断言除数是否为0
int n = 2 / 0;
}
//销毁
@After public void destory() {
m = 0;
n = 0;
}
}
当然,JUnit还有许多新的特性,限于篇幅原因,这里只对比较重要的特性进行讲解,其余将不再多讲,想要了解的读者可以到JUnit的相关网站进行学习。
8.5 小结
本章首先讲述了JUnit的下载和安装,接着又讲解了JUnit的相关知识,最后讲解了JUnit的新特性。
JUnit对开发人员进行大规模的单元测试来说,是非常有用的,但对于大量的代码如何来管理就只有靠CVS了。
1.为什么要使用JUnit
以前,开发人员写一个方法,如下代码所示:
//******* AddAndSub.java**************
public Class AddAndSub {
public static int add(int m, int n) {
int num = m + n;
return num;
}
public static int sub(int m, int n) {
int num = m - n;
return num;
}
}
如果要对AddAndSub类的add和sub方法进行测试,通常要在main里编写相应的测试方法,如下代码所示:
//******* MathComputer.java**************
public Class AddAndSub {
public static int add(int m, int n) {
int num = m + n;
return num;
}
public static int sub(int m, int n) {
int num = m - n;
return num;
}
public static void main(String args[]) {
if (add (4, 6) == 10)) {
System.out.println(“Test Ok”);
} else {
System.out.println(“Test Fail”);
}
if (sub (6, 4) ==2)) {
System.out.println(“Test Ok”);
} else {
System.out.println(“Test Fail”);
}
}
}
从上面的测试可以看出,业务代码和测试代码放在一起,对于复杂的业务逻辑,一方面代码量会非常庞大,另一方面测试代码会显得比较凌乱,而JUnit就能改变这样的状况,它提供了更好的方法来进行单元测试。使用JUnit来测试前面代码的示例如下:
//******* TestAddAndSub.java**************
import junit.framework.TestCase;
public Class TestAddAndSub extends TestCase {
public void testadd() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(4, 6));
}
public void testsub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(6, 4));
}
public static void main(String args[]){
junit.textui.TestRunner.run(TestAddAndSub .class); }
}
这里先不对JUnit的使用方法进行讲解,从上可以看到,测试代码和业务代码分离开,使得代码比较清晰,如果将JUnit放在Eclipse中,测试起来将会更加方便。
2 建立JUnit的开发环境
2.1 下载JUnit
从www.junit.org可以进入到JUnit的首页。
本书使用的版本是4.3版本,单击“Junit4.3.zip”即可进入下载JUnit的画面。
下载Junit4.3.zip,下载后解压缩即可。
2.2 配置JUnit
下载Junit4.3.zip完毕,并解压缩到D盘根目录下后,即可开始配置环境变量。用前面介绍的设定系统变量的方法,设定ClassPath,ClassPath=***;D:\junit\junit.jar,如图8.3所示。
查看是否配置好JUnit,在类里添加如下语句:
import junit.framework.TestCase;
图8.3 设定系统变量ClassPath
如果编译没有错误,则说明配置成功。
3 JUnit的使用方法
JUnit的使用非常简单,共有3步:第一步、编写测试类,使其继承TestCase;第二步、编写测试方法,使用test+×××的方式来命名测试方法;第三步、编写断言。如果测试方法有公用的变量等需要初始化和销毁,则可以使用setUp,tearDown方法。
3.1 继承TestCase
如果要使用JUnit,则测试类都必须继承TestCase。当然目前的最新版JUnit是不需要继承它的,但并不是说TestCase类就没有用了,它仍然是JUnit工作的基础。这里先讲述继承TestCase类的方式,稍后再介绍不继承的方式。
下面是前面使用JUnit进行测试AddAndSub类的代码,这里进行详细的分析:
//******* TestAddAndSub.java**************
import junit.framework.TestCase;
public Class TestAddAndSub extends TestCase {
public void testadd() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(4, 6));
}
public void testsub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(6, 4));
}
public static void main(String args[]){
junit.textui.TestRunner.run(TestAddAndSub .class); }
}
代码说明:
— 这里继承TestCase,表示该类是一个测试类。
— 然后使用junit.textui.TestRunner.run方法来执行这个测试类。
这里给出TestCase的源代码:
//******* TestCase.java**************
package junit.framework;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public abstract class TestCase extends Assert implements Test {
/**测试案例的名称*/
private String fName;
/**构造函数
*/
public TestCase() {
fName= null;
}
/**带参数的构造函数
*/
public TestCase(String name) {
fName= name;
}
/**获取被run执行的测试案例的数量
*/
public int countTestCases() {
return 1;
}
/**创建一个TestResult
* @see TestResult
*/
protected TestResult createResult() {
return new TestResult();
}
/**执行run方法,返回TestResult
* @see TestResult
*/
public TestResult run() {
TestResult result= createResult();
圆角矩形: 下面一段代码描述了JUnit如何实现在执行具体的测试方法前,先执行初始化方法,在执行完具体的测试方法后,再执行销毁方法. run(result);
return result;
}
/**执行run方法,参数为TestResult
*/
public void run(TestResult result) {
result.run(this);
}
/**执行测试方法,包括初始化和销毁方法
* @throws Throwable if any exception is thrown
*/
public void runBare() throws Throwable {
Throwable exception= null;
setUp();
try {
runTest();
} catch (Throwable running) {
exception= running;
}
finally {
try {
tearDown();
} catch (Throwable tearingDown) {
if (exception == null) exception= tearingDown;
}
}
if (exception != null) throw exception;
}
/**执行测试方法
* @throws Throwable if any exception is thrown
*/
protected void runTest() throws Throwable {
assertNotNull("TestCase.fName cannot be null", fName); // Some VMs crash when calling getMethod(null,null);
Method runMethod= null;
try {
//利用反射机制
runMethod= getClass().getMethod(fName, (Class[])null);
} catch (NoSuchMethodException e) {
fail("Method \""+fName+"\" not found");
}
if (!Modifier.isPublic(runMethod.getModifiers())) {
fail("Method \""+fName+"\" should be public");
}
//利用反射机制
try {
runMethod.invoke(this);
}
catch (InvocationTargetException e) {
e.fillInStackTrace();
throw e.getTargetException();
圆角矩形: 下面一段代码定义了要想实现初始化和销毁方法,需继承这两个方法. }
catch (IllegalAccessException e) {
e.fillInStackTrace();
throw e;
}
}
/**测试前的初始化方法
*/
protected void setUp() throws Exception {
}
/**测试后的销毁方法
*/
protected void tearDown() throws Exception {
}
/**返回测试案例的名称
* @return the name of the TestCase
*/
public String getName() {
return fName;
}
/**设定测试案例的名称
* @param name the name to set
*/
public void setName(String name) {
fName= name;
}
}
代码说明:
— 该类继承了Assert 类,实现了Test接口。
— 可以看出,TestCase类正是通过runBare实现了在测试方法前初始化相关变量和环境,在测试方法后销毁相关变量和环境
3.2 编写测试方法
测试方法名要以test+方法名来命名,当然最新版的JUnit支持直接以方法名来命名测试方法。这是通过TestCase类里的runTest方法来实现的,主要利用了Java的反射机制,runTest方法的代码如下:
protected void runTest() throws Throwable {
assertNotNull("TestCase.fName cannot be null", fName); // Some VMs crash when calling getMethod(null,null);
Method runMethod= null;
try {
// 获取要测试的方法
runMethod= getClass().getMethod(fName, (Class[])null);
} catch (NoSuchMethodException e) {
fail("Method \""+fName+"\" not found");
}
//判断要测试的方法是否为公用方法
if (!Modifier.isPublic(runMethod.getModifiers())) {
fail("Method \""+fName+"\" should be public");
}
//Java的反射机制
try {
runMethod.invoke(this);
}
//抛出调用异常
catch (InvocationTargetException e) {
e.fillInStackTrace();
throw e.getTargetException();
}
catch (IllegalAccessException e) {
e.fillInStackTrace();
throw e;
}
}
3.3 编写断言
JUnit主要有以下断言:
— assertEquals(期望值,实际值),检查两个值是否相等。
— assertEquals(期望对象,实际对象),检查两个对象是否相等,利用对象的equals()方法进行判断。
— assertSame(期望对象,实际对象),检查具有相同内存地址的两个对象是否相等,利用内存地址进行判断,注意和上面assertEquals方法的区别。
— assertNotSame(期望对象,实际对象),检查两个对象是否不相等。
— assertNull(对象1,对象2),检查一个对象是否为空。
— assertNotNull(对象1,对象2),检查一个对象是否不为空。
— assertTrue(布尔条件),检查布尔条件是否为真。
— assertFalse(布尔条件),检查布尔条件是否为假。
这些断言主要定义在JUnit的Assert类里,Assert类的示例代码如下:
//******* Assert.java**************
package junit.framework;
/**一系列的断言方法
*/
public class Assert {
/**构造函数
*/
protected Assert() {
}
/**断言是否为真,带消息
*/
static public void assertTrue(String message, boolean condition) {
if (!condition)
fail(message);
}
/**断言是否为真
*/
static public void assertTrue(boolean condition) {
assertTrue(null, condition);
}
/**断言是否为假,带消息
*/
static public void assertFalse(String message, boolean condition) {
assertTrue(message, !condition);
}
/**断言是否为假
*/
static public void assertFalse(boolean condition) {
assertFalse(null, condition);
}
圆角矩形: 下面一段代码描述了如何在JUnit中实现判断是否相等的方法,这些方法要实现的内容相同,只是参数不同,从而实现了可以针对不同类型的数据来判断是否相等的功能. /**断言是否为失败
*/
static public void fail(String message) {
throw new AssertionFailedError(message);
}
/**断言是否为失败
*/
static public void fail() {
fail(null);
}
/**是否相等的断言,带消息Object
*/
static public void assertEquals(String message, Object expected, Object actual) {
if (expected == null && actual == null)
return;
if (expected != null && expected.equals(actual))
return;
failNotEquals(message, expected, actual);
}
/**是否相等的断言,Object
*/
static public void assertEquals(Object expected, Object actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息String
*/
static public void assertEquals(String message, String expected, String actual) {
if (expected == null && actual == null)
return;
if (expected != null && expected.equals(actual))
return;
throw new ComparisonFailure(message, expected, actual);
}
/**是否相等的断言,String
*/
static public void assertEquals(String expected, String actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息double
*/
static public void assertEquals(String message, double expected, double actual, double delta) {
if (Double.compare(expected, actual) == 0)
return;
if (!(Math.abs(expected-actual) <= delta))
failNotEquals(message, new Double(expected), new Double(actual));
}
/**是否相等的断言,double
*/
static public void assertEquals(double expected, double actual, double delta) {
assertEquals(null, expected, actual, delta);
}
/**是否相等的断言,带消息float
*/
static public void assertEquals(String message, float expected, float actual, float delta) {
if (Float.compare(expected, actual) == 0)
return;
if (!(Math.abs(expected - actual) <= delta))
failNotEquals(message, new Float(expected), new Float(actual));
}
/**是否相等的断言, float
*/
static public void assertEquals(float expected, float actual, float delta) {
assertEquals(null, expected, actual, delta);
}
/**是否相等的断言,带消息long
*/
static public void assertEquals(String message, long expected, long actual) {
assertEquals(message, new Long(expected), new Long(actual));
}
/**是否相等的断言, long
*/
static public void assertEquals(long expected, long actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息boolean
*/
static public void assertEquals(String message, boolean expected, boolean actual) {
assertEquals(message, Boolean.valueOf(expected), Boolean.valueOf(actual));
}
/**是否相等的断言,boolean
*/
static public void assertEquals(boolean expected, boolean actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息byte
*/
static public void assertEquals(String message, byte expected, byte actual) {
assertEquals(message, new Byte(expected), new Byte(actual));
}
/**是否相等的断言, byte
*/
static public void assertEquals(byte expected, byte actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息char
*/
static public void assertEquals(String message, char expected, char actual) {
assertEquals(message, new Character(expected), new Character(actual));
}
/**是否相等的断言,char
*/
static public void assertEquals(char expected, char actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息short
*/
static public void assertEquals(String message, short expected, short actual) {
assertEquals(message, new Short(expected), new Short(actual));
}
/**是否相等的断言,short
static public void assertEquals(short expected, short actual) {
assertEquals(null, expected, actual);
}
/**是否相等的断言,带消息int
*/
static public void assertEquals(String message, int expected, int actual) {
assertEquals(message, new Integer(expected), new Integer(actual));
}
/**是否相等的断言,int
*/
static public void assertEquals(int expected, int actual) {
assertEquals(null, expected, actual);
}
圆角矩形: 下面一段代码描述了JUnit中如何实现判断是否为null的方法,这些方法的功能相同,只是一个带消息,一个不带消息. /**是否不为null的断言 Object
*/
static public void assertNotNull(Object object) {
assertNotNull(null, object);
}
/**是否不为null的断言,带消息Object
*/
static public void assertNotNull(String message, Object object) {
assertTrue(message, object != null);
}
/**是否为null的断言Object
*/
圆角矩形: 下面一段代码描述了JUnit中如何实现判断是否相同的方法,这些方法要实现的内容相同,只是参数不同. static public void assertNull(Object object) {
assertNull(null, object);
}
/**是否为null的断言,带消息Object
*/
static public void assertNull(String message, Object object) {
assertTrue(message, object == null);
}
/**是否相同的断言,带消息*/
static public void assertSame(String message, Object expected, Object actual) {
if (expected == actual)
return;
failNotSame(message, expected, actual);
}
/**是否相同的断言,Object
*/
static public void assertSame(Object expected, Object actual) {
assertSame(null, expected, actual);
}
/**是否不相同的断言,带消息
*/
static public void assertNotSame(String message, Object expected, Object actual) {
if (expected == actual)
failSame(message);
}
/**是否不相同的断言Object
*/
static public void assertNotSame(Object expected, Object actual) {
assertNotSame(null, expected, actual);
}
/**相同时失败
*/
static public void failSame(String message) {
String formatted= "";
if (message != null)
formatted= message+" ";
fail(formatted+"expected not same");
}
/**不相同时失败
*/
static public void failNotSame(String message, Object expected, Object actual) {
String formatted= "";
if (message != null)
formatted= message+" ";
fail(formatted+"expected same:<"+expected+"> was not:<"+actual+">");
}
/**不相等时失败
*/
static public void failNotEquals(String message, Object expected, Object actual) {
fail(format(message, expected, actual));
}
/**格式化消息
*/
public static String format(String message, Object expected, Object actual) {
String formatted= "";
if (message != null)
formatted= message+" ";
return formatted+"expected:<"+expected+"> but was:<"+actual+">";
}
}
从上述代码中,读者可以研读JUnit中有关断言的实现方式,其实,最终都是使用后面的几个static方法来实现的。
Java 5的发布为JUnit带来了新的特性。自JUnit 4.0之后,JUnit大量使用了annotations特性,使编写单元测试变得更加简单。
4.1 改变测试方法的命名方式
前面讲过,使用JUnit 4.0以上版本可以不用遵循以前JUnit约定的测试方法命名方法,以前命名方法的示例代码如下:
//******* TestAddAndSub.java**************
import junit.framework.TestCase;
public class TestAddAndSub extends TestCase {
public void testadd() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(4, 6));
}
public void testsub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(6, 4));
}
public static void main(String args[]){
junit.textui.TestRunner.run(TestAddAndSub .class); }
}
JUnit 4.0以上版本的命名方式,是在测试方法前使用@Test注释,示例代码如下:
//******* TestAddAndSub.java**************
import junit.framework.TestCase;
import org.junit.*;
public class TestAddAndSub extends TestCase {
@Test public void add() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(4, 6));
}
@Test public void sub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(6, 4));
}
}
这个时候,测试方法的命名将不再重要,开发人员可以按照自己的命名方式来命名。
4.2 不再继承TestCase
新版本的JUnit将不再强制继承TestCase,但需要import org.junit.Assert来实现断言,示例代码如下:
//******* TestAddAndSub.java**************
import static org.junit.Assert.assertEquals;
import org.junit.*;
public class TestAddAndSub{
@Test public void add() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(4, 6));
}
@Test public void sub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(6, 4));
}
}
4.3 改变初始化和销毁方式
以前,JUnit使用SetUp和TearDown方法来进行初始化和销毁动作,JUnit 4.0以上版本将不再强制使用SetUp和TearDown方法来进行初始化和销毁,原来使用SetUp和TearDown方法的示例代码如下:
//******* TestAddAndSub.java**************
import junit.framework.TestCase;
public class TestAddAndSub extends TestCase {
private int m = 0;
private int n = 0;
//初始化
protected void setUp() {
m = 4;
n = 6;
}
public void testadd() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(m, n));
}
public void testsub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(n, m));
}
//销毁
protected void tearDown() {
m = 0;
n = 0;
}
}
不使用SetUp和TearDown方法的示例代码如下:
//******* TestAddAndSub.java**************
import static org.junit.Assert.assertEquals;
import org.junit.*;
public class TestAddAndSub {
protected int m = 0;
protected int n = 0;
//初始化
@Before public void init() {
m = 4;
n = 6;
}
@Test public void add() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(m, n));
}
@Test public void sub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(n, m));
}
//销毁
@After public void destory() {
m = 0;
n = 0;
}
}
上面示例中的初始化和销毁都是针对一个方法来说的,每个方法执行前都要进行初始化,执行完毕都要进行销毁。而JUnit的最新版本则提供了新的特性,针对类进行初始化和销毁。也就是说,该类中的方法只进行一次初始化和销毁,方法就是使用@Before和@After,示例代码如下:
//******* TestAddAndSub.java**************
import static org.junit.Assert.assertEquals;
import org.junit.*;
public class TestAddAndSub {
protected int m = 0;
protected int n = 0;
//初始化
@BeforeClass public void init() {
m = 4;
n = 6;
}
@Test public void add() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(m, n));
}
@Test public void sub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(n, m));
}
//销毁
@AfterClass public void destory() {
m = 0;
n = 0;
}
}
上述初始化和销毁动作,只执行一次即可。
4.4 改变异常处理的方式
以前,使用JUnit进行单元测试时,如果遇到异常情况,需要使用try…catch的形式来捕捉异常,示例代码如下:
//******* TestAddAndSub.java**************
import junit.framework.TestCase;
public class TestAddAndSub extends TestCase {
private int m = 0;
private int n = 0;
//初始化
protected void setUp() {
m = 4;
n = 6;
}
public void testadd() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(m, n));
}
public void testsub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(n, m));
}
public void testdiv() {
//断言除数为0
try {
int n = 2 / 0;
fail("Divided by zero!");
}
catch (ArithmeticException success) {
assertNotNull(success.getMessage());
}
}
//销毁
protected void tearDown() {
m = 0;
n = 0;
}
}
JUnit4.0以后的版本将不再使用try…catch的方式来捕捉异常,示例代码如下:
//******* TestAddAndSub.java**************
import static org.junit.Assert.assertEquals;
import org.junit.*;
public class TestAddAndSub {
protected int m = 0;
protected int n = 0;
//初始化
@Before public void init() {
m = 4;
n = 6;
}
@Test public void add() {
//断言计算结果与10是否相等
assertEquals(10, AddAndSub.add(m, n));
}
@Test public void sub() {
//断言计算结果与2是否相等
assertEquals(2, AddAndSub.sub(n, m));
}
@Test t(expected=ArithmeticException.class) public void div() {
//断言除数是否为0
int n = 2 / 0;
}
//销毁
@After public void destory() {
m = 0;
n = 0;
}
}
当然,JUnit还有许多新的特性,限于篇幅原因,这里只对比较重要的特性进行讲解,其余将不再多讲,想要了解的读者可以到JUnit的相关网站进行学习。
8.5 小结
本章首先讲述了JUnit的下载和安装,接着又讲解了JUnit的相关知识,最后讲解了JUnit的新特性。
JUnit对开发人员进行大规模的单元测试来说,是非常有用的,但对于大量的代码如何来管理就只有靠CVS了。
评论
3 楼
hanmiao
2013-10-09
代码那叫壹個乱,就不能用下高亮工具嘛...
2 楼
stormtoy
2011-02-26
谢谢,使用方法写得很详细,管理代码用svn也不错
1 楼
kensunhu
2010-11-21
谢谢你的文章!
相关推荐
本指南将详细解析Junit的使用方法,旨在帮助开发者快速上手并熟练运用。 一、Junit简介 Junit是由Eclipse基金会维护的开源项目,它基于Java编程语言,主要用于编写和运行针对Java类的单元测试。通过Junit,开发者...
在这个示例中,我们将学习如何使用 JUnit 来测试一个方法的多种情况。首先,添加一个类 WordDealUtil,包含一个方法 wordFormat4DB(),该方法的实现见文件注释。然后,编写单元测试代码,使用 JUnit 来测试该方法的...
JUnit4 使用方法 JUnit4 是一个流行的 Java 单元测试框架,提供了许多功能强大且灵活的测试工具。本文将详细介绍 JUnit4 的使用方法和核心概念。 JUnit4 核心概念 JUnit4 的核心概念包括测试类、测试集和测试运行...
本文将详细介绍如何使用 Junit 测试 `void` 类型的方法,并提供一个具体的示例。 #### 理解问题:为何无法直接测试 `void` 方法 在 Junit 中,大部分的测试都是基于断言来进行的,即通过比较预期结果和实际结果来...
同时,虽然JUnit可以独立于集成开发环境(IDE)使用,但Eclipse是一个非常流行的选择,因为它内置了对JUnit的支持,特别是从Eclipse 3.2版本开始就支持JUnit 4。这里以Eclipse Helios (3.6) for Java EE为例,讲解...
本教程文档详细介绍了JUnit的基本使用方法,适用于初学者快速上手。 首先,要了解JUnit的核心概念,包括测试类、测试方法和断言。测试类通常会继承自`junit.framework.TestCase`(在较新版本的JUnit5中,使用`org....
在本文中,我们将深入探讨JUnit 4.10及其使用方法,帮助你更好地理解和应用这个强大的测试工具。 首先,了解JUnit的基本概念。单元测试是对软件中的最小可测试部分——通常是一个函数、一个方法或者一个模块——...
**Junit使用说明文档** **一、Junit简介** JUnit是一款广泛应用于Java编程语言的单元测试框架,由Ernst Konig和Kent Beck在2000年开发。它是XUnit系列测试框架的一员,旨在帮助开发者对代码进行快速、可靠且可重复...
JUNIT JUNIT 固件的安装与拆除 (测试方法启动和结束之前要做的) (测试方法启动和结束之前要做的) .... .... 6 Eclipse Eclipse 中使用 junit junitjunit (有了开发工具对 (有了开发工具对 junit的支持后) .....
### JUnit单元测试使用方法详解 #### 一、JUnit简介及意义 JUnit 是一个流行的 Java 编程语言的单元测试框架。它最初由 Erich Gamma 和 Kent Beck 创建,旨在简化软件开发过程中的测试工作。单元测试是软件开发...
5. **断言结果**:在JUnit测试中,我们可以使用`assertEquals()`等断言方法,验证私有方法执行后的结果是否符合预期。 下面是一个简单的例子,展示如何使用JUnit测试私有方法: ```java import org.junit.Test; ...
jUnit4 在 Eclipse 中的使用教程 jUnit4 是 JUnit 框架有史以来的最大改进,其主要目标便是利用 Java5 的 Annotation 特性简化测试用例的编写。 Annotation 是一种元数据,描述数据的数据。在 Java 里面可以用来和 ...
Bosent Junit 使用是指在 Bosent 环境中使用 Junit 进行单元测试的方法。Junit 是一个流行的 Java 单元测试框架, 可以帮助开发者快速、方便地编写单元测试用例。 启动方式 Bosent Junit 使用的启动方式与 Bosent ...
在`JUnit & 简单Junit使用代码`这个文件中,可能包含了一个或多个示例,展示了如何创建测试类、编写测试方法、使用断言以及设置测试环境。例如,可能有一个简单的数学操作类`MathUtils`,以及对应的测试类`...
### JUnit参数化测试的使用方法 #### 一、引言 JUnit是Java开发中最常用的单元测试框架之一,它提供了一种简单的方式来编写可重复执行的测试案例。随着软件复杂度的增加,对于某些功能模块可能需要多次使用不同的...
本教程将详细介绍如何使用JUnit以及在MyEclipse中配置和运行JUnit测试。 首先,我们需要了解JUnit的基本概念。JUnit是一个开源的Java库,它提供了注解(Annotation)和断言(Assertion)等工具,帮助我们定义和执行...