說起單元測試,剛畢業或者沒畢業的人可能大多停留在課本講述的定義階段,至於具體是怎麼定義的,估計也不會有太多人記得。我們的教育總是這樣讓人“欣慰”。那麼什麼是單元測試呢?具體科學的定義咱就不去關心了,其實每個寫代碼的人都在時刻進行著單元測試,除非你從來不驗證自己寫的代碼能否達到預期目的,而是直接寫完就完事兒了,連run一下都不進行。
單元測試說的直白一點,就是驗證寫得一段代碼是否正確,可能是一個類,可能是一個函數,甚至可能是一個迴圈。為了測試的方便,我們一般直接就在寫好的可運行代碼中直接進行測試,看到控制台輸出了預想的結果或者拋出了異常。但是進入了公司,這樣的測試方法極不專業也不不容易複現測試環境。那麼可能需要專門寫一個測試類別,調用你想測試的代碼單元,然後進行測試。但是這樣每次都需要建立類,編寫測試案例,相當之麻煩。
說了這麼多,福利來了。單元測試工具——JUnit。協助我們進行單元測試,提供諸多便利。下面介紹如何在Eclipse中利用JUnit進行單元測試。
假如,我們編寫了一個Calculator,提供一些簡單的計算機功能。代碼如下,故意留一些bug。
1 package org.logback.test; 2 3 public class Calculator { 4 5 private static int result; 6 // 靜態變數,用於儲存運行結果 7 8 public void add(int n) { 9 10 result = result + n;11 12 }13 14 public void substract(int n) {15 16 result = result - 1; //Bug: 正確的應該是 result = result-n17 18 }19 20 public void multiply(int n) {21 22 } // 此方法尚未實現23 24 public void divide(int n) {25 26 result = result / n;27 28 }29 30 public void square(int n) {31 32 result = n * n;33 34 }35 36 public void squareRoot(int n) {37 38 for (; ;) ; //Bug : 死迴圈39 40 }41 42 public void clear() { // 將結果清零43 44 result = 0;45 46 }47 48 public int getResult() {49 50 return result;51 52 }53 }
那麼要對這個類在現有開發程度下進行單元測試了,方法很簡單,首先在該類所屬的工程名上右鍵進入Properties。
在彈出的Properties視窗,左側選擇Java Build Path,然後右側選擇Libraries標籤卡,最後選擇Add Library。
在彈出的Add Library視窗中,選擇JUnit點擊Next,然後在下拉式功能表中選擇JUnit4,點擊Finish。
這樣JUnit就被引入了項目的Libraries中,點擊OK。在要進行測試的那個類上右鍵,選擇new→JUnit Test Case。
在彈出的建立視窗中按如下設定,具體含義稍後講解
這裡可以選擇將測試類別放在專門的測試包中,並且給測試類別起一個顯而易見的名字。選擇Next,然後進入了。
此處是選擇要測試的方法,假如我們只測試加減乘除4個方法,則勾選對應的4個方法,點擊Finish。則自動產生了一個測試類別,不過我們仍需對此類進行一定的修改,將該測試類別最終修改為如下代碼
1 package org.logback.test; 2 3 import static org.junit.Assert.*; 4 5 import org.junit.After; 6 import org.junit.AfterClass; 7 import org.junit.Before; 8 import org.junit.BeforeClass; 9 import org.junit.Ignore;10 import org.junit.Test;11 12 public class CalculatorTest {13 14 private static Calculator example = new Calculator();15 16 @Before//在每個測試方法執行前先執行的方法17 public void setUp() throws Exception {18 example.clear();19 }20 21 @After//在每個測試方法執行後立刻執行的方法22 public void setDown(){23 System.out.println("over");24 }25 26 @BeforeClass //在類載入的時候調用的方法,必須public和static的,只調用一次27 public static void start(){28 System.out.println("start class");29 }30 31 @AfterClass //在類結束的時候調用的方法,必須public和static的,只調用一次32 public static void destory(){33 System.out.println("destory class");34 }35 36 @Test37 public void testAdd() {38 example.add(2);39 example.add(3);40 assertEquals(5, example.getResult());41 }42 43 @Test44 public void testSubstract() {45 example.add(10);46 example.substract(2);47 assertEquals(8, example.getResult());48 }49 50 @Ignore//因該方法暫未實現而忽略測試51 @Test52 public void testMultiply() {53 fail("Not yet implemented");54 }55 56 @Test57 public void testDivide() {58 example.add(8);59 example.divide(2);60 assertEquals(4, example.getResult());61 }62 63 @Test(timeout = 1000)//設定時間限制,單位是毫秒,逾時即算測試失敗64 public void testsquareRoot(){65 example.squareRoot(4);66 assertEquals(2, example.getResult());67 }68 69 @Test(expected = ArithmeticException.class)//測試是否能如期拋出該異常70 public void divideByZero(){71 example.divide(0);//除數為0,如能正確拋出異常,則測試通過,否則測試失敗72 }73 }
每個方法都有注釋,以標明其具體用途。
為了要測試Calculator的功能,所以需要先建立一個對應的執行個體,就如14行所做的那樣。代碼中出現了很多@開頭的東西,下面簡單介紹一下。以@開頭的稱為標註,是JDK1.5引入的特性,簡介一下JUnit中常用的標註的含義:
@Test 標註的方法為測試方法,包含屬性timeout(用於設定時間限制,以毫秒為單位,超過限制時間,該測試則以失敗返回)、expected(設定此處應該拋出的異常,如果真拋出了該異常,則測試成功,否則失敗)
@Before 標註的方法會在每個測試方法執行前先執行一次
@After 標註的方法會在每個測試方法執行結束後執行一次
@BeforeClass 標註的方法會在類載入的時候執行一次,且僅此一次,該方法必須是public和static的
@AfterClass 標註的方法會在類銷毀的時候執行一次,且僅此一次,該方法必須是public和static的
@Ignore 標註的方法表示因為要測試的方法仍未實現而忽略測試
@Parameters 標註的方法用於定義測試資料集合,一般用來給一個測試方法傳遞多組測試資料
以上標註都是用來標註方法的,下面介紹兩個用來標註類的:
@RunWith(classname.class) 指定此測試採用什麼運行器,如果不設定,則採用預設的運行器,就像我們上一個例子中那樣。
@Suite.SuiteClasses({
TestClassName1.class,
TestClassName2.class,
...
}) 打包測試,有時會遇到同一個類的測試類別有很多個,逐個運行測試太麻煩了,那就通過這種方式將所有要啟動並執行測試類別一起運行。文章後面會給出例子。
介紹完標註之後,再來看一下測試方法中用到的assertEquals的功能。該方法有兩個參數,第一個是預期的值,第二個是傳遞給方法的結果,用以比對方法處理後的結果與預期是否一致,因此來返回測試是否成功還是失敗。
用之前的代碼進行測試,步驟如下:
在類中右鍵Run As → JUnit Test
可以看到左側JUnit標籤出現如所示結果:
最上方的深紅色進度條,表示有測試方法返回失敗。然後列出了6個測試方法,藍色X表示預期與實際結果不相同,紅色X表示超過了限制條件(此處是逾時了,因為測試方法調用的方法裡面有死迴圈),綠色√表示該測試方法成功,灰色/表示該測試方法被忽略。點擊列表中對應的方法名時,下方Failure Trace會給出錯誤資訊。
上述例子是針對測試的方法不需要多組資料的情況。OK,今天先這麼多!改天繼續~