因?yàn)楣ぷ骱蛯W(xué)習(xí)的需要,在代碼中查錯(cuò)的時(shí)候,第一步就是想知道這個(gè)錯(cuò)誤具體發(fā)生在一個(gè)位置,進(jìn)行一個(gè)準(zhǔn)確的定位。而這個(gè)定位的工作交給誰(shuí)來(lái)做了呢?不難猜出也就是這篇博客的主題---Junit。junit是一個(gè)開(kāi)源的框架,也是java這一塊的測(cè)試工具之一。想了解詳細(xì)請(qǐng)上官網(wǎng),下面用代碼來(lái)跟大家解釋。
準(zhǔn)備要測(cè)試的方法,放進(jìn)一個(gè)類(lèi)中方便于測(cè)試。
package com.junit3_8; /** * junt3.8單元測(cè)試 * * @author CHH * @since 2013-01-19 * */ public class Calculator { // 加 public int add(int a, int b) { int sum=0; for(int i=0;i<100;i++){ sum +=i; } System.out.println("加=="+sum); return a+b; } // 減 public int subtract(int a, int b) { int sum=0; for(int i=0;i<100;i++){ sum +=i; } System.out.println("減=="+sum); return a - b; } // 乘 public int multiply(int a, int b) { int sum=0; for(int i=0;i<100;i++){ sum +=i; } System.out.println("乘==="+sum); return a * b; } // 除 public int divide(int a, int b) throws Exception { int sum=0; for(int i=0;i<100;i++){ sum +=i; } System.out.println("除==="+sum); if (0 == b) { throw new Exception("除數(shù)不能為0"); } return a / b; } }
Junit3.8測(cè)試類(lèi)
package com.junit3_8; import junit.framework.Assert; import junit.framework.TestCase; /** * * @author CHH * @since 2013-01-19 */ public class CalculatorTest extends TestCase { Calculator cal; //在“每個(gè)”測(cè)試方法執(zhí)行之前被調(diào)用 public void setUp() { //這段代碼在這寫(xiě)比較方便,只寫(xiě)一次就夠, //不用在每個(gè)方法里寫(xiě),因?yàn)檫@個(gè)方法每次都被調(diào)用,生成不同的對(duì)象,供測(cè)試方法使用 cal = new Calculator(); } //在“每個(gè)”測(cè)試方法執(zhí)行之后被調(diào)用 public void tearDown() { } //測(cè)試方法:方法名要以test為開(kāi)頭,無(wú)參數(shù),無(wú)返回類(lèi)型 public void testAdd() { //Calculator cal = new Calculator(); int result = cal.add(1, 2); //第一個(gè)參數(shù)是預(yù)期的,第二個(gè)參數(shù)是真實(shí)的 Assert.assertEquals(3, result); //Assert.fail(); } public void testSubtract() { //Calculator cal = new Calculator(); int result = cal.subtract(1, 2); //第一個(gè)參數(shù)是預(yù)期的,第二個(gè)參數(shù)是真實(shí)的 Assert.assertEquals(-1, result); } public void testMultiply() { //Calculator cal = new Calculator(); int result = cal.multiply(1, 2); //第一個(gè)參數(shù)是預(yù)期的,第二個(gè)參數(shù)是真實(shí)的 Assert.assertEquals(2, result); } public void testDivide() { int result = 0; //Calculator cal = new Calculator(); try { result = cal.divide(4, 2); } catch(Exception e) { e.printStackTrace(); //讓測(cè)試失敗 Assert.fail(); } //第一個(gè)參數(shù)是預(yù)期的,第二個(gè)參數(shù)是真實(shí)的 Assert.assertEquals(2, result); } //除數(shù)為0的情況 public void testDivideByZero() { Throwable th = null ; //Calculator cal = new Calculator(); try { cal.divide(1, 0); Assert.fail(); } catch(Exception e) { th = e ; //e.printStackTrace(); } //th 不為空 null Assert.assertNotNull(th); //第一個(gè)參數(shù)是預(yù)期的,第二個(gè)參數(shù)是真實(shí)的 Assert.assertEquals(Exception.class, th.getClass()); Assert.assertEquals("除數(shù)不能為0", th.getMessage()); } //加了這個(gè)main方法,可以直接以 Java Application 方式運(yùn)行 ,也可以以 JUnit Test 運(yùn)行 public static void main(String[] args) { //命令行形式打印 junit.textui.TestRunner.run(CalculatorTest.class); //awt 界面方式顯示 //junit.awtui.TestRunner.run(CalculatorTest.class); //swing 界面方式顯示 //junit.swingui.TestRunner.run(CalculatorTest.class); } }
從上面的代碼中可以看出Junit測(cè)試類(lèi)是通過(guò)繼承一個(gè)TestCase類(lèi)來(lái)實(shí)現(xiàn)方法的測(cè)試,而這就是Junit4.0以前的測(cè)試方式,而在4.0之后他們的實(shí)現(xiàn)方式又有了稍微的變化。
Junit4.0之后不再是通過(guò)繼承TestCase的方式來(lái)實(shí)現(xiàn)方法的實(shí)測(cè),而是采用注解的方式進(jìn)行的。根據(jù)Java 5.0中的新特征(注解,靜態(tài)導(dǎo)入等),Junit開(kāi)發(fā)團(tuán)隊(duì)也隨之靠攏,采用注解的方式來(lái)進(jìn)行方法的測(cè)試。這樣下來(lái)相比而言JUnit 4更簡(jiǎn)單、更豐富和更易于使用。
Junit4.0測(cè)試類(lèi)
package com.junit4_0;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
/**
* Junit4.0
* @author CHH
* @since 2013-01-19 晚上10:12
*
*/
public class CalculatorTest {
private static Calculator calculator = new Calculator();
//每個(gè)方法測(cè)試前調(diào)用
@Before
public void clearCalculator() {
calculator.clear();
}
//每個(gè)方法測(cè)試完以后調(diào)用
@After
public void tearDown()
{
}
//@Test:測(cè)試方法,表明這是一個(gè)測(cè)試方法。在Junit中將會(huì)自動(dòng)被執(zhí)行。
@Test
public void add() {
calculator.add(1);
calculator.add(1);
//第一個(gè)參數(shù)是預(yù)期的,第二個(gè)參數(shù)是真實(shí)的
assertEquals(calculator.getResult(), 2);
}
@Test
public void subtract() {
calculator.add(10);
calculator.substract(2);
//第一個(gè)參數(shù)是預(yù)期的,第二個(gè)參數(shù)是真實(shí)的
assertEquals(calculator.getResult(), 8);
}
//給測(cè)試函數(shù)設(shè)定一個(gè)執(zhí)行時(shí)間,超過(guò)了這個(gè)時(shí)間(400毫秒),它們就會(huì)被系統(tǒng)強(qiáng)行終止
@Test(timeout=400)
public void divide() {
calculator.add(8);
calculator.divide(2);
//第一個(gè)參數(shù)是預(yù)期的,第二個(gè)參數(shù)是真實(shí)的
assert calculator.getResult() == 5;
}
//使用注釋來(lái)聲明該異常是預(yù)期的,異常測(cè)試是Junit4中的最大改進(jìn)
@Test(expected = ArithmeticException.class)
public void divideByZero() {
calculator.divide(0);
}
//@Ignore:忽略的測(cè)試方法,標(biāo)注的含義就是“某些方法尚未完成,暫不參與此次測(cè)試”
@Ignore("not ready yet")
@Test
public void multiply() {
calculator.add(10);
calculator.multiply(10);
//第一個(gè)參數(shù)是預(yù)期的,第二個(gè)參數(shù)是真實(shí)的
assertEquals(calculator.getResult(), 100);
}
}
Junit4出了采用的注解的方式來(lái)進(jìn)行測(cè)試方法之外,還增加了一些新的元素。
A、JUnit4添加了兩個(gè)比較數(shù)組的assert() 方法:
public static void assertEquals(Object[] expected, Object[] actual)
public static void assertEquals(String message, Object[] expected, Object[] actual)
Junit4常用注解:
@Test 測(cè)試方法,表明這是一個(gè)測(cè)試方法。在Junit中將會(huì)自動(dòng)被執(zhí)行。
@Test(timeOut=400) 給測(cè)試函數(shù)設(shè)定一個(gè)執(zhí)行時(shí)間,超過(guò)了這個(gè)時(shí)間(400毫秒),它們就會(huì)被系統(tǒng)強(qiáng)行終止
@Test(expected = ArithmeticException.class) 使用注釋來(lái)聲明該異常是預(yù)期的,異常測(cè)試是Junit4中的最大改進(jìn)
@Ignore("not ready yet") 忽略的測(cè)試方法,標(biāo)注的含義就是“某些方法尚未完成,暫不參與此次測(cè)試”
@Before 每個(gè)方法測(cè)試前調(diào)用
@After 每個(gè)方法測(cè)試完以后調(diào)用
@BeforeClass 每個(gè)類(lèi)運(yùn)行前調(diào)用,并且只調(diào)用一次
@AfterClass 每個(gè)類(lèi)運(yùn)行后調(diào)用,并且只調(diào)用一次
表格.@BeforeClass/@AfterClass比較于@Before/@After。
@BeforeClass和@AfterClass | @Before和@After |
在每個(gè)類(lèi)中只有一個(gè)方法能被注解。 | 多個(gè)方法能被注解,但其執(zhí)行的順序未特別指定,且不運(yùn)行重載方法。 |
方法名是不相關(guān)的 | 方法名是不相關(guān)的 |
每個(gè)類(lèi)運(yùn)行一次 | 在每個(gè)測(cè)試方法運(yùn)行前或運(yùn)行后運(yùn)行 |
在當(dāng)前類(lèi)的@BeforeClass方法運(yùn)行前先運(yùn)行超類(lèi)的@BeforeClass方法。在超類(lèi)中聲明的@AfterClass方法將在所有當(dāng)前類(lèi)的該方法運(yùn)行后才運(yùn)行。 | 超類(lèi)中的@Before在所有子類(lèi)的該方法運(yùn)行前運(yùn)行。在超類(lèi)中的@After在在所有子類(lèi)的該方法運(yùn)行后才運(yùn)行。 |
必須是公共和非靜態(tài)的。 | 必須是公共和非靜態(tài)的。 |
即使一個(gè)@BeforeClass方法拋出一個(gè)異常,所有的@AfterClass方法也保證被運(yùn)行。 | 即使一個(gè)@Before或者@Test方法拋出一個(gè)異常,所有的@After方法也保證被運(yùn)行。 |
總結(jié):這兩個(gè)版本最大的區(qū)別在JUnit3.x中測(cè)試必須繼承 TestCase,并且每個(gè)方法名必須以test開(kāi)頭。比如:testMethod1()而在JUnit4.x中不必繼承TestCase,采用了注解的 方式。只要在測(cè)試的方法上加上注解@Test即可,從而不必再遵循以前的一些顯式約定和反射定位測(cè)試;在JUnit4.x中如果繼承了TestCase, 注解就不起作用了。
并且有很重要的一點(diǎn)就是在JUnit4.x中繼承了TestCase后,在OutLine視圖中測(cè)試單個(gè)方法時(shí),結(jié)果整個(gè)類(lèi)都run 了。還有一點(diǎn)就是,在3.x中需要實(shí)現(xiàn)setUp和tearDown方法,而在4.x中無(wú)需這樣,可以自定義需要在測(cè)試前和測(cè)試后的方法,在方法前加上 @before,@after就可以了。所以在JUnit4.x不必繼承TestCase用注解即可對(duì)單個(gè)方法進(jìn)行測(cè)試