前一篇文章咱們整體介紹了Junit4的用法以及一些簡單的測試。以前我有個疑惑,Junit4怎麼把一個test case跑起來的,在test case以前和以後咱們能作些什麼?html
Junit4執行順序是怎樣的?帶着這些問題,我寫了這篇文章,僅供參考,不對之處,盼留言指正,感激萬分。前一篇文章:【原創】Junit4詳解一:Junit整體介紹java
Junit4編譯器在執行TestCase的過程當中利用反射機制,以便咱們能夠對測試的開始過程當中進行一些預處理,如讀取元數據信息,攔截異常,數據庫操做等,因爲Junit4默認的測試執行器是:BlockJUnit4ClassRunner,咱們以這個執行器粗略地作一些研究。在TestCase執行過程當中,主要用到如下類,BlockJUnit4ClassRunner,ParentRunner,Statement,TestRule,Description,RunNotifier,InvokeMethod.如下簡單作些解釋。數據庫
1. BlockJUnit4ClassRunner:Junit4的默認測試執行器,它有以前版本的runner一樣的行爲,也就兼容了以前的runner。可是它是基於Statement,實現更加簡單,容許用戶在執行工做流中某個合適的點插入用戶新的操做,基於這個runner的繼承和重用都是能夠的,這樣能更加具備靈活性。它繼承ParentRunner,Junit4要求,執行器的構造函數要把測試類傳進來。這個類的實現了ParentRunner的runChild(真正執行測試的方法,每一個測試方法都會執行runChild),describeChild(FrameworkMethod method)(用來獲取測試類的元數據信息,以及方法和類的信息),一些驗證的方法,這些驗證方法在ParentRunner構造的時候就會開始驗證。另一個比較重要的方法是:app
methodBlock(FrameworkMethod method)ide
method裏面包含當前要測試的方法。函數
這個方法的做用驗證方法可否執行,而後把當前測試類的信息(當前類,測試的方法)傳給InvokeMethod,以待後續測試方法的執行,接着獲取當前類的元數據信息,保存起來。post
2. ParentRunner:Junit4測試執行器的基類,它提供了一個測試器所須要的大部分功能。繼承它的類須要實現:測試
protected abstract List<T> getChildren();ui
protected abstract Description describeChild(T child);this
protected abstract void runChild(T child, RunNotifier notifier);
3. Statement:在運行期時,執行test case前能夠插入一些用戶動做,它就是描述這些動做的一個類。繼承這個類要實現:
/** * Run the action, throwing a {@code Throwable} if anything goes wrong. */ public abstract void evaluate() throws Throwable;
這個方法,這個方法會前後在ParentRunner.run()和ParentRunner.runLeaf()這兩個方法裏面調用。另外,咱們能夠自定義一個Statement,而且實現evaluate()方法。
4. TestRule:TestRule能夠描述一個或多個測試方法如何運行和報告信息的接口。在TestRule中能夠額外加入一些check,咱們可讓一個test case失敗/成功,也能夠加入一些setup和cleanup要作的事,也能夠加入一些log之類的報告信息。總之,跑test case以前的任何事,均可以在裏面作。須要實現apply()方法。
/** * Modifies the method-running {@link Statement} to implement this * test-running rule. * @param base The {@link Statement} to be modified * @param description A {@link Description} of the test implemented in {@code base} * @return a new statement, which may be the same as {@code base}, * a wrapper around {@code base}, or a completely new Statement. */ Statement apply(Statement base, Description description);
這兩個類的用法能夠見後面的綜合例子。
5. Description:存儲着當前單個或多個test case的描述信息。這些信息跟邏輯不關,好比元數據信息等。實例化Description用Description.createTestDescription()方法。
6. RunNotifier:運行時通知器。執行Runner.run(RunNotifier runNotifier)方法時,須要傳一個RunNotifier進去,這個RunNotifier是事件的管理器,它能幫助咱們監控測試執行的狀況。
7. InvokeMethod:最終執行test case裏面的測試方法經過這個類來作,這個類會間接調用Method.invoke()方法通知編譯器執行@test方法。
@Rule public final TestRule testRule = new CommonRule();
此時,咱們就能夠在咱們新構建的CommonRule類裏面,的apply()方法,作一些對test的預處理,好比預處理鏈接數據庫字符串,讀取方法上元數據的信息等;
備註:就如剛所說的,真正開始測試前,咱們能夠用apply()進行一些處理,一樣地,咱們能夠在apply()方法中,建立用戶Statement,這樣就能在evaluate()方法中,作一些操做。如執行腳本,日誌等。
1. 獲取元數據信息的順序
@BeforeClass -> @AfterClass -> ClassRule -> @Test(拿元數據裏的expect Exception) -> @Test(拿元數據裏的timeout信息) -> @Before -> @After -> @Rule,
2. 註解所標註的方法執行順序
@ClassRule(TestRule.apply()) -> @BeforeClass -> @Rule(TestRule.apply()) -> @Before -> @Test(test method1) ->@After -> if existed @Rule, then Statement.evaluate() -> @Rule(TestRule.apply()) -> @Before -> @Test(test method2) -> @After -> if existed @Rule, then Statement.evaluate() … -> @AfterClass -> if existed @ClassRule, then Statement.evaluate()
經過Statement.evaluate()執行他們的方法實體,最終執行測試方法的主體。
附錄:
TestRule Statement以及註解標識的方法執行順序代碼示例
1 package com.citi.risk.services.credit.facility.impl; 2 3 import java.io.Closeable; 4 import java.io.IOException; 5 6 import org.junit.After; 7 import org.junit.AfterClass; 8 import org.junit.Before; 9 import org.junit.BeforeClass; 10 import org.junit.ClassRule; 11 import org.junit.Rule; 12 import org.junit.Test; 13 import org.junit.rules.ExpectedException; 14 import org.junit.rules.TestRule; 15 import org.junit.runner.Description; 16 import org.junit.runners.model.Statement; 17 18 /** 19 * 執行順序以下: 默認test方法的執行順序是隨機的,沒有順序 20 * @ClassRule(TestRule.apply()) -> @BeforeClass -> @Rule(TestRule.apply()) -> @Before 21 * -> @Test(test method1) ->@After -> if existed @Rule, then Statement.evaluate() 22 * -> @Rule(TestRule.apply()) -> @Before -> @Test(test method2) -> @After 23 * -> if existed @Rule, then Statement.evaluate() … -> @AfterClass 24 * -> if existed @ClassRule, then Statement.evaluate() 25 * @author 草原戰狼 26 * 27 */ 28 public class TestClass { 29 30 @Rule 31 public ExpectedException expectedException = ExpectedException.none(); 32 33 @Rule 34 public TestRule testRule = new TestRuleValueImpl(); 35 36 @Rule 37 public TestRule testRuleMethod() { 38 System.out.println(); 39 System.out.println("@Rule Method"); 40 return new TestRuleMethodImpl(); 41 } 42 @ClassRule 43 public static TestRule testClassRuleMethod() { 44 System.out.println("@ClassRule Method"); 45 return new TestRuleMethodImpl(); 46 } 47 48 static class TestRuleValueImpl implements TestRule{ 49 @Override 50 public Statement apply(Statement base, Description description) { 51 System.out.println("@Rule property--TestRuleValueImpl execute apply()"); 52 return new StatementValueImpl(base); 53 } 54 } 55 56 static class StatementValueImpl extends Statement { 57 Statement base; 58 StatementValueImpl(Statement base) { 59 this.base = base; 60 } 61 @Override 62 public void evaluate() throws Throwable { 63 System.out.println("@Rule property--StatementValueImpl execute evaluate()"); 64 base.evaluate(); 65 } 66 67 } 68 static class TestRuleMethodImpl implements TestRule{ 69 @Override 70 public Statement apply(Statement base, Description description) { 71 System.out.println("@Rule method--TestRuleMethodImpl execute apply()"); 72 return new StatementMethodImpl(base); 73 } 74 75 } 76 77 static class StatementMethodImpl extends Statement { 78 Statement base; 79 StatementMethodImpl(Statement base) { 80 this.base = base; 81 } 82 @Override 83 public void evaluate() throws Throwable { 84 System.out.println("@Rule Method--StatementMethodImpl execute evaluate()"); 85 base.evaluate(); 86 } 87 88 } 89 static class ExpensiveManagedResource implements Closeable { 90 @Override 91 public void close() throws IOException { 92 } 93 } 94 95 static class ManagedResource implements Closeable { 96 @Override 97 public void close() throws IOException { 98 } 99 } 100 101 @BeforeClass 102 public static void setUpClass() { 103 System.out.println("@BeforeClass setUpClass"); 104 myExpensiveManagedResource = new ExpensiveManagedResource(); 105 } 106 107 @AfterClass 108 public static void tearDownClass() throws IOException { 109 System.out.println("@AfterClass tearDownClass"); 110 myExpensiveManagedResource.close(); 111 myExpensiveManagedResource = null; 112 } 113 114 private ManagedResource myManagedResource; 115 private static ExpensiveManagedResource myExpensiveManagedResource; 116 117 private void println(String string) { 118 System.out.println(string); 119 } 120 121 @Before 122 public void setUp() { 123 this.println("@Before setUp"); 124 this.myManagedResource = new ManagedResource(); 125 } 126 127 @After 128 public void tearDown() throws IOException { 129 this.println("@After tearDown"); 130 this.myManagedResource.close(); 131 this.myManagedResource = null; 132 this.println(" "); 133 } 134 135 @Test 136 public void test1() { 137 this.println(" @Test test1() begin"); 138 this.println(" @Test test1() execute during evaluate()"); 139 this.println(" @Test test1() finished"); 140 } 141 142 @Test 143 public void test2() { 144 this.println(" @Test test2() begin"); 145 this.println(" @Test test2() execute during evaluate()"); 146 this.println(" @Test test2() finished"); 147 } 148 149 @Test 150 public void test3() { 151 this.println(" @Test test3() begin"); 152 String hi = " @Test test3() execute during evaluate()"; 153 expectedException.expect(Exception.class); 154 expectedException.expectMessage("ddd"); 155 this.println(hi); 156 this.println(" @Test test3() finished."); 157 } 158 }
執行的結果以下:
1 @ClassRule Method 2 @Rule method--TestRuleMethodImpl execute apply() 3 @Rule Method--StatementMethodImpl execute evaluate() 4 @BeforeClass setUpClass // 預備期結束 5 // 第一個測試方法開始到結束
6 @Rule Method 7 @Rule method--TestRuleMethodImpl execute apply() 8 @Rule property--TestRuleValueImpl execute apply() 9 @Rule property--StatementValueImpl execute evaluate() 10 @Rule Method--StatementMethodImpl execute evaluate() 11 @Before setUp 12 @Test test1() begin 13 @Test test1() execute during evaluate() 14 @Test test1() finished 15 @After tearDown 16
17 // 第二個方法開始到結束,咱們能夠在apply() 和 evaluate()這兩個方法作一些操做。
18 @Rule Method 19 @Rule method--TestRuleMethodImpl execute apply() 20 @Rule property--TestRuleValueImpl execute apply() 21 @Rule property--StatementValueImpl execute evaluate() 22 @Rule Method--StatementMethodImpl execute evaluate() 23 @Before setUp 24 @Test test2() begin 25 @Test test2() execute during evaluate() 26 @Test test2() finished 27 @After tearDown 28
29 // 第三個方法,這三個方法執行的順序是隨機的,固然Junit4提供了某些排序方式能夠處理
30 @Rule Method 31 @Rule method--TestRuleMethodImpl execute apply() 32 @Rule property--TestRuleValueImpl execute apply() 33 @Rule property--StatementValueImpl execute evaluate() 34 @Rule Method--StatementMethodImpl execute evaluate() 35 @Before setUp 36 @Test test3() begin 37 @Test test3() execute during evaluate() 38 @Test test3() finished. 39 @After tearDown 40
41 @AfterClass tearDownClass
草原戰狼淘寶小店:http://xarxf.taobao.com/ 淘寶搜小矮人鞋坊,主營精緻美麗時尚女鞋,爲您的白雪公主挑一雙哦。謝謝各位博友的支持。
====================================================================================
====================== 以上分析僅表明我的觀點,歡迎指正與交流 =========================
====================== 草原戰狼博客,轉載請註明出處,萬分感謝 =========================
====================================================================================