JUnit基礎及第一個單元測試實例(JUnit3.8)
單元測試
單元測試(unit testing) ,是指對軟件中的最小可測試單元進行檢查和驗證。
單元測試不是為了證明您是對的,而是為了證明您沒有錯誤。
單元測試主要是用來判斷程序的執行結果與自己期望的結果是否一致。
關鍵是在於所用的測試用例(Test Case) 。
JUnit
JUnit是一個Java語言的單元測試框架。
項目主頁:http://junit.org/
Java的很多IDE,比如Eclipse集成了JUnit,只需要在build path中添加Library並選擇想用的版本即可。
JUnit的兩種主要版本是JUnit 3.8和JUnit 4,前者使用反射,后者使用反射和注解。
博文回顧:本博客上次介紹JUnit的時候是在反射和注解之后:
http://www.cnblogs.com/mengdd/archive/2013/02/02/2890204.html
結合實例來說明單元測試的用法:
1.編寫目標類源代碼
新建一個項目,起名叫JUnitTest,首先編寫一個目標類Calculator:
package com.mengdd.junit; public class Calculator { public int add(int a, int b) { return a + b; } public int subtract(int a, int b) { return a - b; } public int multiply(int a, int b) { return a * b; } public int divide(int a, int b) { return a / b; } }
2.添加JUnit庫
然后為了使用JUnit,需要加入庫:
右鍵選擇項目Properties->左側Java Build Path->標簽Libraries->Add Library...
彈出的對話框中選JUnit,然后Next,再選擇JUnit 3或者JUnit 4.
本文示例選擇JUnit 3。
3.創建測試類
這里需要注意以下幾點:
1.使用JUnit的最佳實踐:源代碼和測試代碼需要分開。
所以可以新建一個名叫test的source folder,用於存放測試類源代碼。這樣在發布程序的時候測試類的程序就可以丟掉了。
但是這兩個文件夾中的類編譯出的class文件都會在同一個bin文件夾中。
2.測試類和目標源代碼的類應該位於同一個包下面,即它們的包名應該一樣。
這樣測試類中就不必導入源代碼所在的包,因為它們位於同一個包下面。
3.測試類的命名規則:
在要測試的類名之前或之后加上Test。
此步驟完成后項目目錄如下:
4.測試類代碼編寫
測試類必須繼承於TestCase類。
TestCase文檔說明:
public abstract class TestCase
extends Assert
implements Test
A test case defines the fixture to run multiple tests.
To define a test case
1) implement a subclass of TestCase
2) define instance variables that store the state of the fixture
3) initialize the fixture state by overriding setUp
4) clean-up after a test by overriding tearDown.
Each test runs in its own fixture so there can be no side effects among test runs.
(本文最后參考資料中會給出JUnit文檔的網盤鏈接,有需要可下載)
還有一個很重要的Assert類,參見文檔,全是static void方法。
對於測試類中方法的要求:
在JUnit 3.8中,測試方法需要滿足如下原則:
1.public的。
2.void的。
3.無方法參數。
4.方法名稱必須以test開頭。 (它通過反射找出所有方法,然后找出以test開頭的方法)。
Test Case之間一定要保持完全的獨立性,不允許出現任何的依賴關系。
刪除一些方法后不會對其他的方法產生任何的影響。
我們不能依賴於測試方法的執行順序。
綜上,編寫代碼如下:
package com.mengdd.junit; import junit.framework.Assert; import junit.framework.TestCase; public class CalculatorTest extends TestCase { public void testAdd() { Calculator calculator = new Calculator(); int result = calculator.add(1, 2); // 判斷方法的返回結果 Assert.assertEquals(3, result);// 第一個參數是期望值,第二個參數是要驗證的值 } public void testSubtract() { Calculator calculator = new Calculator(); int result = calculator.subtract(1, 2); // 判斷方法的返回結果 Assert.assertEquals(-1, result);// 第一個參數是期望值,第二個參數是要驗證的值 } public void testMultiply() { Calculator calculator = new Calculator(); int result = calculator.multiply(2, 3); // 判斷方法的返回結果 Assert.assertEquals(6, result);// 第一個參數是期望值,第二個參數是要驗證的值 } public void testDivide() { Calculator calculator = new Calculator(); int result = calculator.divide(12, 3); // 判斷方法的返回結果 Assert.assertEquals(4, result);// 第一個參數是期望值,第二個參數是要驗證的值 } }
運行一下:右鍵選擇該類,Run As->JUnit Test
(可以在此處右鍵選擇Run重復運行)
JUnit的口號:Keep the bar green to keep the code clean.
5.代碼重構:setUp()方法的使用
有一個原則:DRY(Don’t Repeat Yourself)
所以對代碼進行重構,將重復的生成對象的部分放在setUp()方法中。
(重寫的時候將protected變為public,繼承的時候擴大訪問范圍是沒有問題的。)
先進行一個方法的測試測試:
在CalculatorTest類中加入代碼如下:
@Override public void setUp() throws Exception { System.out.println("set up"); } @Override public void tearDown() throws Exception { System.out.println("tear down"); }
再次運行后發現Console中輸出如下:
說明這兩個方法執行了多次。
在每個測試用例之前執行setUp(),每個測試用例執行之后,tearDown()會執行。
即對於每個測試用例,執行順序為:
1.setUp()
2.testXXX()
3.tearDown()
重構:使用成員變量生成對象(為了能在每個方法中都用到),將生成對象的語句放在setUp()中,注意這里為每一個測試用例都會生成新的對象。
重構后代碼如下:
package com.mengdd.junit; import junit.framework.Assert; import junit.framework.TestCase; public class CalculatorTest extends TestCase { private Calculator calculator = null; @Override public void setUp() throws Exception { System.out.println("set up"); // 生成成員變量的實例 calculator = new Calculator(); System.out.println(calculator); } @Override public void tearDown() throws Exception { System.out.println("tear down"); } public void testAdd() { int result = calculator.add(1, 2); // 判斷方法的返回結果 Assert.assertEquals(3, result);// 第一個參數是期望值,第二個參數是要驗證的值 } public void testSubtract() { int result = calculator.subtract(1, 2); // 判斷方法的返回結果 Assert.assertEquals(-1, result);// 第一個參數是期望值,第二個參數是要驗證的值 } public void testMultiply() { int result = calculator.multiply(2, 3); // 判斷方法的返回結果 Assert.assertEquals(6, result);// 第一個參數是期望值,第二個參數是要驗證的值 } public void testDivide() { int result = calculator.divide(12, 3); // 判斷方法的返回結果 Assert.assertEquals(4, result);// 第一個參數是期望值,第二個參數是要驗證的值 } }
運行后控制台輸出:
說明每一個測試的方法前后都會有setUp()和tearDown()方法的調用,所以每次生成的都是一個新的對象,各個方法之間沒有干擾。
參考資料
聖思園張龍老師Unit Test系列視頻教程。
CHM格式文檔網盤鏈接:
JUnit 3.8.1:http://pan.baidu.com/share/link?shareid=539342&uk=2701745266
JUnit 4.0:http://pan.baidu.com/share/link?shareid=539345&uk=2701745266