Junit目前在一些大的公司或者相對規範的軟件中使用的比較多,至關多的小公司並無把單元測試看的過重要。在大點的公司開發人員天天上班後,第一件事情就是從svn上把本身負責的代碼checkout下來,而後運行單元測試,若是單元測試經過,那麼說明本身的代碼沒有問題,而後就在代碼塊上修改與添加,完成後再用junit進行測試,測試完成後若是沒有問題,那麼就把相應的代碼塊提交給svn上。java
測試通常分爲:單元測試、集成測試(主要看一塊代碼加進去後,系統會不會有問題)、驗收測試和壓力測試。數組
在之前的的項目中也用過Junit,當時的使用只是把Junit當成一個有多個main方法的一個函數。假如一個項目很是的大,測試的東西很是的多,若是不用Junit的話,那麼這個工做量是很是大的。單元測試的最基本的一個功能是能進行自動化測試。單元測試都是經過斷言的方式來肯定結果是否正確,即便用Assert。svn
1、創建Junit測試類函數
1. 右擊test測試包,選擇New-->Oher...oop
2. 在窗口中找到Junit,選擇Junit Test Case單元測試
3. 輸入名稱(Name),命名規則通常建議採用:類名+Test。Browse...選擇要測試的類,這裏是StudentService。測試
4. 勾選要測試的方法ui
5. 生成後,效果以下:this
這裏import static是引入Assert類中靜態屬性或靜態方法的寫法。原來要Assert.fail(),如今只需直接fial()便可,即省略了Assert。spa
其實不經過Junit新建嚮導來創建也能夠,隨便創建一個新類後,只需在方法上加入@Test註解便可。
2、核心——斷言
斷言是編寫測試用例的核心實現方式,即指望值是多少,測試的結果是多少,以此來判斷測試是否經過。
1. 斷言核心方法
assertArrayEquals(expecteds, actuals) | 查看兩個數組是否相等。 |
assertEquals(expected, actual) | 查看兩個對象是否相等。相似於字符串比較使用的equals()方法 |
assertNotEquals(first, second) | 查看兩個對象是否不相等。 |
assertNull(object) | 查看對象是否爲空。 |
assertNotNull(object) | 查看對象是否不爲空。 |
assertSame(expected, actual) | 查看兩個對象的引用是否相等。相似於使用「==」比較兩個對象 |
assertNotSame(unexpected, actual) | 查看兩個對象的引用是否不相等。相似於使用「!=」比較兩個對象 |
assertTrue(condition) | 查看運行結果是否爲true。 |
assertFalse(condition) | 查看運行結果是否爲false。 |
assertThat(actual, matcher) | 查看實際值是否知足指定的條件 |
fail() | 讓測試失敗 |
2. 示例
- package test;
- import static org.hamcrest.CoreMatchers.*;
- import static org.junit.Assert.*;
- import java.util.Arrays;
- import org.hamcrest.core.CombinableMatcher;
- import org.junit.Test;
- public class AssertTests {
- @Test
- public void testAssertArrayEquals() {
- byte[] expected = "trial".getBytes();
- byte[] actual = "trial".getBytes();
- org.junit.Assert.assertArrayEquals("failure - byte arrays not same", expected, actual);
- }
- @Test
- public void testAssertEquals() {
- org.junit.Assert.assertEquals("failure - strings not same", 5l, 5l);
- }
- @Test
- public void testAssertFalse() {
- org.junit.Assert.assertFalse("failure - should be false", false);
- }
- @Test
- public void testAssertNotNull() {
- org.junit.Assert.assertNotNull("should not be null", new Object());
- }
- @Test
- public void testAssertNotSame() {
- org.junit.Assert.assertNotSame("should not be same Object", new Object(), new Object());
- }
- @Test
- public void testAssertNull() {
- org.junit.Assert.assertNull("should be null", null);
- }
- @Test
- public void testAssertSame() {
- Integer aNumber = Integer.valueOf(768);
- org.junit.Assert.assertSame("should be same", aNumber, aNumber);
- }
- // JUnit Matchers assertThat
- @Test
- public void testAssertThatBothContainsString() {
- org.junit.Assert.assertThat("albumen", both(containsString("a")).and(containsString("b")));
- }
- @Test
- public void testAssertThathasItemsContainsString() {
- org.junit.Assert.assertThat(Arrays.asList("one", "two", "three"), hasItems("one", "three"));
- }
- @Test
- public void testAssertThatEveryItemContainsString() {
- org.junit.Assert.assertThat(Arrays.asList(new String[] { "fun", "ban", "net" }), everyItem(containsString("n")));
- }
- // Core Hamcrest Matchers with assertThat
- @Test
- public void testAssertThatHamcrestCoreMatchers() {
- assertThat("good", allOf(equalTo("good"), startsWith("good")));
- assertThat("good", not(allOf(equalTo("bad"), equalTo("good"))));
- assertThat("good", anyOf(equalTo("bad"), equalTo("good")));
- assertThat(7, not(CombinableMatcher.<Integer> either(equalTo(3)).or(equalTo(4))));
- assertThat(new Object(), not(sameInstance(new Object())));
- }
- }
3、核心——註解
1. 說明
@Before | 初始化方法 |
@After | 釋放資源 |
@Test | 測試方法,在這裏能夠測試指望異常和超時時間 |
@Ignore | 忽略的測試方法 |
@BeforeClass | 針對全部測試,只執行一次,且必須爲static void |
@AfterClass | 針對全部測試,只執行一次,且必須爲static void |
@RunWith | 指定測試類使用某個運行器 |
@Parameters | 指定測試類的測試數據集合 |
@Rule | 容許靈活添加或從新定義測試類中的每一個測試方法的行爲 |
@FixMethodOrder | 指定測試方法的執行順序 |
2. 執行順序
一個測試類單元測試的執行順序爲:
@BeforeClass –> @Before –> @Test –> @After –> @AfterClass
每個測試方法的調用順序爲:
@Before –> @Test –> @After
3. 示例
- package test;
- import static org.junit.Assert.*;
- import org.junit.*;
- public class JDemoTest {
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- System.out.println("in BeforeClass================");
- }
- @AfterClass
- public static void tearDownAfterClass() throws Exception {
- System.out.println("in AfterClass=================");
- }
- @Before
- public void before() {
- System.out.println("in Before");
- }
- @After
- public void after() {
- System.out.println("in After");
- }
- @Test(timeout = 10000)
- public void testadd() {
- JDemo a = new JDemo();
- assertEquals(6, a.add(3, 3));
- System.out.println("in Test ----Add");
- }
- @Test
- public void testdivision() {
- JDemo a = new JDemo();
- assertEquals(3, a.division(6, 2));
- System.out.println("in Test ----Division");
- }
- @Ignore
- @Test
- public void test_ignore() {
- JDemo a = new JDemo();
- assertEquals(6, a.add(1, 5));
- System.out.println("in test_ignore");
- }
- @Test
- public void teest_fail() {
- fail();
- }
- }
- class JDemo extends Thread {
- int result;
- public int add(int a, int b) {
- try {
- sleep(1000);
- result = a + b;
- } catch (InterruptedException e) {
- }
- return result;
- }
- public int division(int a, int b) {
- return result = a / b;
- }
- }
執行結果:
- in BeforeClass================
- in Before
- in Test ----Add
- in After
- in Before
- in Test ----Division
- in After
- in AfterClass=================
圖中左上紅框中部分表示Junit運行結果,5個成功(1個忽略),1個錯誤,1個失敗。(注意錯誤和失敗不是一回事,錯誤說明代碼有錯誤,而失敗表示該測試方法測試失敗)
左下紅框中則表示出了各個測試方法的運行狀態,能夠看到成功、錯誤、失敗、失敗各自的圖標是不同的,還能夠看到運行時間。
右邊部分則是異常堆棧,可查看異常信息。
4、實例總結
1. 參數化測試
有時一個測試方法,不一樣的參數值會產生不一樣的結果,那麼咱們爲了測試全面,會把多個參數值都寫出來並一一斷言測試,這樣有時不免費時費力,這是咱們即可以採用參數化測試來解決這個問題。參數化測試就比如把一個「輸入值,指望值」的集合傳入給測試方法,達到一次性測試的目的。
- package test;
- import static org.junit.Assert.*;
- import java.util.Arrays;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.junit.runners.Parameterized;
- import org.junit.runners.Parameterized.Parameters;
- @RunWith(Parameterized.class)
- public class FibonacciTest {
- @Parameters(name = "{index}: fib({0})={1}")
- public static Iterable<Object[]> data() {
- return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
- { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
- }
- private int input;
- private int expected;
- public FibonacciTest(int input, int expected) {
- this.input = input;
- this.expected = expected;
- }
- @Test
- public void test() {
- assertEquals(expected, Fibonacci.compute(input));
- }
- }
- class Fibonacci {
- public static int compute(int input) {
- int result;
- switch (input) {
- case 0:
- result = 0;
- break;
- case 1:
- case 2:
- result = 1;
- break;
- case 3:
- result = 2;
- break;
- case 4:
- result = 3;
- break;
- case 5:
- result = 5;
- break;
- case 6:
- result = 8;
- break;
- default:
- result = 0;
- }
- return result;
- }
- }
@Parameters註解參數name,實際是測試方法名稱。因爲一個test()方法就完成了全部測試,那假如某一組測試數據有問題,那在Junit的結果頁面裏該如何呈現?所以採用name實際上就是區分每一個測試數據的測試方法名。以下圖:
2. 打包測試
一樣,若是一個項目中有不少個測試用例,若是一個個測試也很麻煩,所以打包測試就是一次性測試完成包中含有的全部測試用例。
- package test;
- import org.junit.runner.RunWith;
- import org.junit.runners.Suite;
- @RunWith(Suite.class)
- @Suite.SuiteClasses({ AssertTests.class, FibonacciTest.class, JDemoTest.class })
- public class AllCaseTest {
- }
這個功能也須要使用一個特殊的Runner ,須要向@RunWith註解傳遞一個參數Suite.class 。同時,咱們還須要另一個註解@Suite.SuiteClasses,來代表這個類是一個打包測試類。並將須要打包的類做爲參數傳遞給該註解就能夠了。至於AllCaseTest隨便起一個類名,內容爲空既可。運行AllCaseTest類便可完成打包測試
3. 異常測試
異常測試與普通斷言測試不一樣,共有三種方法,其中最爲靈活的是第三種,能夠與斷言結合使用
第一種:
- @Test(expected= IndexOutOfBoundsException.class)
- public void empty() {
- new ArrayList<Object>().get(0);
- }
第二種:
- @Test
- public void testExceptionMessage() {
- try {
- new ArrayList<Object>().get(0);
- fail("Expected an IndexOutOfBoundsException to be thrown");
- } catch (IndexOutOfBoundsException anIndexOutOfBoundsException) {
- assertThat(anIndexOutOfBoundsException.getMessage(), is("Index: 0, Size: 0"));
- }
- }
第三種:
- @Rule
- public ExpectedException thrown = ExpectedException.none();
- @Test
- public void shouldTestExceptionMessage() throws IndexOutOfBoundsException {
- List<Object> list = new ArrayList<Object>();
- thrown.expect(IndexOutOfBoundsException.class);
- thrown.expectMessage("Index: 0, Size: 0");
- list.get(0);
- Assert.assertEquals(1, list.get(0));
- }
在上述幾種方法中,不管是expected仍是expect都表示指望拋出的異常,假如某一方法,當參數爲某一值時會拋出異常,那麼使用第一種方法就必須爲該參數單獨寫一個測試方法來測試異常,而沒法與其餘參數值一同寫在一個測試方法裏,因此顯得累贅。第二種方法雖然解決這個問題,可是寫法不只繁瑣也不利於理解。而第三種犯法,不只能動態更改指望拋出的異常,與斷言語句結合的也很是好,所以推薦使用該方法來測試異常。
4. 限時測試
有時爲了防止出現死循環或者方法執行過長(或檢查方法效率),而須要使用到限時測試。顧名思義,就是超出設定時間即視爲測試失敗。共有兩種寫法。
第一種:
- @Test(timeout=1000)
- public void testWithTimeout() {
- ...
- }
第二種:
- public class HasGlobalTimeout {
- public static String log;
- @Rule
- public Timeout globalTimeout = new Timeout(10000); // 10 seconds max per method tested
- @Test
- public void testInfiniteLoop1() {
- log += "ran1";
- for (;;) {
- }
- }
- @Test
- public void testInfiniteLoop2() {
- log += "ran2";
- for (;;) {
- }
- }
- }
其中,第二種方法與異常測試的第三種方法的寫法相似。也是推薦的寫法。