JUnit官網對JUnit的簡單解釋:java
JUnit is a simple framework to write repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks.設計模式
JUnit是一個簡單的可複用的測試框架,是xUnit測試框架的一個子集。數組
xUnit是一套基於測試驅動開發的測試框架。框架
xUnit包括:PythonUnit、CppUnit等等。JUnit應該算是xUnit家族最成功的一個了。單元測試
使用JUnit可以幫助咱們減小在開發過程當中的錯誤,把Bug扼殺在萌芽之中,有利於代碼的後期維護和檢查。作好了單元測試能夠縮短開發週期,提升代碼質量。這樣咱們就能夠把更多的時間用到咱們應該乾的事情上來而不是去解決項目後期發現的愈來愈多的使人頭疼的問題。測試
測試不是用來證實你是對的,而是用來證實你沒有錯。ui
JUnit官網:http://junit.org/this
首先訪問JUnit官網,找到welcome模塊:spa
而後點擊下載相應版本的JUnit就OK了。設計
準守必定的規則會使咱們的項目和代碼看起來更加的和諧。
通常來講規則是這樣的:
a. 在Java項目(這裏爲JUnitTest)中建立一個名爲test的source folder。
b. 在test目錄中建立和src目錄下相同的包名,在其中存放對應的測試類。
c. 不要忘了引入JUnit及其依賴jar包。
等項目完成以後把test測試源碼文件刪除便可,不影響其餘的代碼。
項目的結構目錄看起來應該是這樣的:
這樣咱們就能夠來進行測試代碼的編寫了。
a.首先在src/util包下建立Calculator.java,編寫一個簡單的加法運算器。
package util; /** *被測試的類 *@author wxisme *@time 2015-9-2 上午9:52:24 */ public class Calculator { public int add(int a, int b) { return a + b; } }
b. 在test/util包下建立CalculatorTest.java做爲Calculator的測試類。
package util; import junit.framework.Assert; import org.junit.Before; import org.junit.Test; import util.Calculator; /** * *@author wxisme *@time 2015-9-1 下午8:44:15 */ public class CalculatorTest { private static Calculator calculator; @BeforeClass public static void BuildCalculator() { calculator = new Calculator(); } @Test public void testAdd() { Assert.assertEquals(8, calculator.add(3, 5)); } }
上面的程序JUnit4提供的註解和方法。
首先看@Test註解,見名知意,是標註testAdd()方法爲一個測試方法。
Assert.assertEquals(8, calculator.add(3, 5));方法是JUnit中Assert類提供的斷言方法。可以判斷咱們的預期結果和程序的輸出結果是不是一致的。
咱們來測試一下:選中testAdd()方法,右鍵選擇run as JUnit test:
上面程序運行的結果應該是這樣的:
看到有綠色的條,而且Error和Failure的值都爲零,說明咱們的測試經過。程序運行結果與咱們所指望的是一致的。
那若是把testAdd()方法中的斷言改爲:
Assert.assertEquals(8, calculator.add(3, 5));
運行結果會是怎樣的呢?
應該是這樣的:
從紅色圈起來的地方咱們能夠得知,測試沒有經過,而且錯誤在於,咱們指望的值爲7,可是程序的輸出結果爲8.
c. 經過上面的例子咱們能夠有一下總結:
測試方法必須使用@Test修飾
測試方法必須使用public void修飾
新建test源代碼目錄來存放測試代碼
測試類的包名應該和被測試類的報名保持一致
測試單元中的每一個方法必須能夠獨立測試,測試方法之間不能有任何依賴
測試類通常使用Test做爲後綴
測試方法通常使用test做爲前綴
JUnit4中提供的經常使用註解大體包括:
@BeforeClass
@AfterClass
@Before
@After
@Test
@Ignore
@RunWith
咱們經過一個例子來了解他們的用法:
編寫一個MethodTest來測試註解的用法。
package util; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; /** * *@author wxisme *@time 2015-9-2 上午11:28:29 */ public class MethodTest { @BeforeClass //用static修飾 public static void setUpBeforeClass() throws Exception { System.out.println("beforeClass..."); } @AfterClass //用static修飾 public static void tearDownAfterClass() throws Exception { System.out.println("afterClass..."); } @Before public void setUp() throws Exception { System.out.println("before..."); } @After public void tearDown() throws Exception { System.out.println("after..."); } @Test public void test1() { System.out.println("test1..."); // fail("Not yet implemented"); } @Test public void test2() { System.out.println("test2..."); // fail("Not yet implemented"); } }
測序的運行後再Console的中輸出以下:
beforeClass...
before...
test1...
after...
before...
test2...
after...
afterClass...
其中咱們能夠總結出這幾個註解的執行順序和做用:
@Test將一個普通的方法修飾爲一個測試方法
@BeforeClass會在全部方法運行前執行,static修飾
@AfterClass會在全部方法運行結束後執行,static修飾
@Before會在每一個測試方法運行前執行一次
@After會在每一個測試方法運行後被執行一次
這就是爲何在第一個例子中我會這麼幹了(全部的測試方法只使用一個Calculator就好了):
private Calculator calculator; @BeforeClass public static void BuildCalculator() { calculator = new Calculator(); }
@Test註解還能夠帶有參數。像這樣:
@Test(expected=xx.class)
@Test(timeout=毫秒)
timeout參數很容易理解,就是指定程序運行的超時時間,單位爲毫秒。
咱們來看一下expected參數。
看一個例子:
在第一個例子裏面加一個Exception異常屬性,在testAdd()方法中拋出。
package util; import junit.framework.Assert; import org.junit.Before; import org.junit.Test; import util.Calculator; /** * *@author wxisme *@time 2015-9-1 下午8:44:15 */ public class CalculatorTest { private static Calculator calculator; private static Exception ex; @BeforeClass public static void BuildCalculator() { calculator = new Calculator(); ex = new Exception("手動拋出的異常!"); } @Test public void testAdd() throws Exception { Assert.assertEquals(8, calculator.add(3, 5)); throw ex; } }
結果會是這樣的:
發現測試沒有經過,而且拋出了一個異常,使咱們手動拋出的異常。
那麼把上面的程序總@Test註解加上這樣的參數:
@Test(expected=Exception.class)
再看結果:
發現測試經過了。
是否是忽然就明白expected參數的做用了呢?
其餘幾個註解的功能能夠類比。
再來看@Ignore和@RunWith
@Ignore見名知意,做用是讓測試運行器忽略其修飾的測試方法。@Ignore所修飾的方法不會執行。
自行測試。
@RunWith能夠用來更改運行測試器org.junit.runner.Runner。
下面的兩個例子都是經過@RunWith註解來實現的。
試想若是項目中有100個測試類須要測試,你會怎麼作呢?每一個類運行一次?運行100次?
JUnit固然不會只容許有這一個愚蠢的方法。答案就是測試套件。
測試套件用來組織批量運行測試類。看一個例子。
首先來建立3個測試類模擬須要批量運行的測試類羣。
public class DemoTest1 { @Test public void test() { System.out.println("DemoTest1..."); } } public class DemoTest2 { @Test public void test() { System.out.println("DemoTest2..."); } } public class DemoTest3 { @Test public void test() { System.out.println("DemoTest3..."); } }
而後建立一個名爲SuiteTest的測試類,並加上@RunWith註解和@Suite.SuiteClasses註解。(該類中沒有其餘測試方法)
package util; import org.junit.runner.RunWith; import org.junit.runners.Suite; /** *測試套件 *@author wxisme *@time 2015-9-2 下午7:37:56 */ @RunWith(Suite.class) @Suite.SuiteClasses({DemoTest1.class,DemoTest2.class,DemoTest3.class}) public class SuiteTest { }
測試程序總首先用@RunWith來修改測試運行器。
而後使用@Suite.SuiteClasses來指定要批量執行的測試類(數組的形式)
程序的運行結果應該是這樣的(經過測試而且在Console中輸出):
可見咱們的批量運行生效了。
再試想一個場景:若是一個測試方法中須要測試100組數據是否和指望值一致,你會怎麼作呢?手動copy+change100次?
JUnit也不會只容許使用這麼愚蠢的方法。這就用到了JUnit的參數化設置。
看一個例子:
a.首先建立一個名爲ParameterTest的測試類,並用RunWith註解來改變測試運行器。
b.聲明變量來存放預期值和結果值。
c.聲明一個返回值爲Collection的公共靜態方法,並使用 @Parameters進行修飾。
d.爲測試類聲明一個帶有參數的公共構造方法,並在其中爲之聲明變量賦值。
代碼應該是這樣的:
package util; import java.util.Arrays; import java.util.Collection; import junit.framework.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; /** *JUnit參數化設置 *@author wxisme *@time 2015-9-2 下午8:03:47 */ @RunWith(Parameterized.class) public class ParameterTest { private static Calculator calculator; @BeforeClass public static void setUpBeforeClass() { calculator = new Calculator(); } private int expected; private int input1; private int input2; @Parameters public static Collection<Object[]> setParameters() { Object[][] objs = {{8,3,5},{5,3,2}}; return Arrays.asList(objs); } public ParameterTest(int expected, int input1, int input2) { this.expected = expected; this.input1 = input1; this.input2 = input2; } @Test public void testParameters() { Assert.assertEquals(expected, calculator.add(input1, input2)); } }
而後咱們運行這個測試類(要在類的級別上運行,若是在方法上運行就會有初始化錯誤)。
結果應該是這樣的:
運行結果顯示兩組測試數據均測試經過。
到此JUnit的基本用法就介紹完了,關於JUnit的其餘用法以及斷言的API請參考官方提供的document(若是你不想本身找的話,在評論區留下郵箱,我會發給你的哦)。
JUnit帶給咱們的不只是開發效率、代碼質量的提升,更是一種思想的提升,如今都在講測試驅動開發、迴歸質量大概就是這種思想。
JUnit使用起來不只簡單方便,其源碼更是短小精悍,Erich Gamma 是著名的 GoF 之一,在JUnit中設計模式的使用堪稱經典,有優良的擴展性和可重用性。值得細細品味。
敬請關注將要發表的《JUnit源碼解析》系列博客(這須要提早了解Java的註解、反射等高級特性)。
@Copyright:http://www.cnblogs.com/wxisme/ 不當之處,歡迎交流。