简要说JUnit的4大功能
1. 管理测试用例。修改了哪些代码,这些代码的修改会对哪些部分有影响,通过JUnit将这次的修改做个完整测试。这也就JUnit中所谓的TestSuite。
2. 定义测试代码。这也就是JUnit中所谓的TestCase,根据源代码的测试需要定义每个TestCase,并将TestCase添加到相应的TestSuite方便管理。
3. 定义测试环境。在TestCase测试前会先调用“环境”配置,在测试中使用,当然也可以在测试用例中直接定义测试环境。
4. 检测测试结果。对于每种正常、异常情况下的测试,运行结果是什么、结果是否是我们预期的等都需要有个明确的定义,JUnit在这方面提供了强大的功能。
以上部分与我们平常使用IDE调试的过程是完全一样的,只不过是增加了测试用例管理、测试结果检测等功能,提高了单元的效率,保证了单元测试的完整性,明确了单元测试的目标。
一. 测试用例
package can.test;
import java.util.ArrayList;
import java.util.Collection;
import junit.framework.TestCase;
publicclass SampleTestextendsTestCase {
protectedvoid setUp() {
/* 开始test前的准备操作:初始化,获取数据连接... */
}
protectedvoid tearDown() {
/* 完成test后的清理工作:关闭文件,关闭数据连接... */
}
publicvoid testEmpty() {
/* test case 1*/
Collectioncollection = new ArrarList();
assertTrue(collection.isEmpty());
}
publicvoid testCase2() {
/* test case 2*/
ArrayListemptyList = new ArrayList();
try {
Objecto = emptyList.get(0);
fail("Should raise anIndexOutOfBoundsException");
}catch (IndexOutOfBoundsException expected) {
assertTrue(true);
}
}
}
1. 当需要进行test前后操作,则对setUp(), tearDown()这两个方法进行重写。
2. 每进行一个testcase前后,都会调用setUp(), tearDown()。注意,不是一次调用setUp(), 然后进行多个test case,最后才调用tearDown()。而且选择test case的次序是不确定的。所以调用次序可能是:
1 setUp()
2 testYYY()
3 tearDown()
4 setUp()
5 testXXX()
6 tearDown()
所以每个testcase不要存在数据上的前后联系。
3. 编译&运行
compile: javac -cp../lib/junit.jar can/junit/ SampleTest.java
run: (文本界面) java -cp .;../lib/junit.jar junit.textui.TestRunner can.junit.SampleTest
(图形界面) java -cp .;../lib/junit.jar junit.swingui.TestRunner can.junit.SampleTest
如果提示can.junit.SampleTest not found,则注意命令中红色处,.表示把当前目录添加到classpath,便于junit能够在该目录找到can.junit.SampleTest
4. 加上main(可选)
如果你觉得每次都要在命令中指定文本界面或图形界面,有点麻烦,那可以添加一下代码到SampleTest类中:
import junit.framework.Test;
import junit.framework.TestSuite;
publicstatic Test suite() {
/* 添加SampleTest类到TestSuite*/
returnnew TestSuite(SampleTest.class);
}
publicstaticvoid main(String args[]) {
/* 指定文本界面*/
junit.textui.TestRunner.run(suite());
}
或者
publicstaticvoid main(String args[]){
junit.textui.TestRunner.run(SampleTest.class);
}
这样run: java -cp .;../lib/junit.jar can.junit. SampleTest
二. 测试单元
当需要对多个类或者模块进行unit test的时候,我们都会写好每个类的testcase,然后写一个Suite来将它们串联起来。
package can.junit;
import junit.framework.Test;
import junit.framework.TestSuite;
publicclass SampleTestSuite {
publicstatic Test suite() {
TestSuitesuite = new TestSuite("Sample Tests");
/* 逐一添加testCase类 */
suite.addTestSuite(SampleTest.class);
/* 逐一添加test suite(注意,这是递归调用的) */
suite.addTest(AnotherTestSuite.suite());
return suite;
}
publicstaticvoid main(String args[]) {
junit.textui.TestRunner.run(suite());
}
}
刚 才说了,每进行一个test case,setUp()和tearDown()都会调用。而有的时候,在setUp()中相当耗费资源,我们想进行所有的test case仅调用一次setUp()和tearDown(),这样需要把TestSuite包装到TestSetup类中:
import junit.framework.*;
import junit.extensions.TestSetup;
publicclass AllTestsOneTimeSetup{
publicstatic Test suite() {
TestSuitesuite = new TestSuite();
suite.addTest(SomeTest.suite());
suite.addTest(AnotherTest.suite());
TestSetupwrapper = new TestSetup(suite){
protectedvoid setUp() {
oneTimeSetUp();
}
protectedvoid tearDown() {
oneTimeTearDown();
}
};
return wrapper;
}
publicstaticvoid oneTimeSetUp() {
// one-time initializationcode
}
publicstaticvoid oneTimeTearDown(){
// one-time cleanupcode
}
}
三. 其他
对于protected方法的test,可以把testcase放在被test的类同一目录。
package JUnit;
import java.util.Collection;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/*
public class TestsAll {
public static Test suite() {
TestSuite suite = new TestSuite("Test for JUnit");
//$JUnit-BEGIN$
//$JUnit-END$
return suite;
}
}
*/
import java.util.Hashtable;
import junit.framework.Assert;
publicclass TestsAllextends TestCase {
/***//**定义你需要测试的类及用到的变量*****************************/
public Hashtablehasha=null;//
public Hashtablehashb=null;
/***//*******************************************************/
public TestsAll(String name){
super(name);//创建子类
}
/***//**用setUp进行初始化操作*/
protectedvoid setUp()throws Exception {
super.setUp();
hasha =new Hashtable();//这里
}
/***//**用tearDown来销毁所占用的资源*/
protectedvoid tearDown()throws Exception {
super.tearDown();
//System.gc();
}
/***//**写一个测试方法断言期望的结果**/
publicvoid testBodyStatus(){
//hasha =new Hashtable();//有此句后也可去掉setUp() tearDown()
assertNotNull(hasha);
//hasha.put("0","let'stry again");//test1.error版
assertTrue(hasha.isEmpty());//期望为空
}
/***//**再写一个测试方法断言期望的结果**/
publicvoid testBodySame(){
//hashb=(Hashtable)hasha.clone(); //test2.error版
hashb=hasha; //test2.OK版
Assert.assertSame(hasha,hashb);
}
/***//**suite()方法,使用反射动态的创建一个包含所有的testXxxx方法的测试套件**/
publicstatic TestSuite suite(){
returnnew TestSuite(TestsAll.class);
}
/***//****写一个main()运行测试*****************/
publicstaticvoid main(String args[]){
junit.textui.TestRunner.run(suite());//以文本运行器的方式方便的
//junit.swingui.TestRunner.run(JunitB.class);
}
}