Spring是如何整合JUnit的?JUnit源碼關聯延伸閱讀
- 2022 年 5 月 21 日
- 筆記
上一篇我們回答了之前在梳理流程時遇到的一些問題,並思考了為什麼要這麼設計。
本篇是《如何高效閱讀源碼》專題的第十二篇,通過項目之間的聯繫來進行擴展閱讀,通過項目與項目之間的聯繫更好的理解項目。
本節內容:
-
TestRunner的執行流程
-
Spring如何整合JUnit
在我們使用Spring的項目中進行測試時,一般都需要添加下面一行註解:
@RunWith(SpringRunner.class
為什麼要使用這個註解呢?為了回答這個問題,我們先來了解一下TestRunner是如何執行的。
TestRunner的執行流程
在前面梳理的執行流程中,我們已經知道了JUnitCore是整個測試的入口,它構建了Runner實例,而Runner通過測試類構建了對應的測試模型,並通過Statement來執行,通過TestNotifier來通知TestListener來處理測試結果。
但是我們還沒有梳理出JUnitCore是如何構建出Runner的,現在我們從JUnitCore入手,將最後一塊拼圖補全,梳理出一個完整的測試執行流程。
入口方法很簡單,委託給了runMain方法來執行。
這裡只是將命令行參數parse為一個對象,然後通過參數配置來執行測試。
注意到這裡的addListener了嗎?這裡構建了一個TextListener,通過addListener添加到了TestNotifier中。前面我們已經知道,測試結果是通過TestNotifier來通知TestListener的,而這裡就是向TestNotifier中添加TestListener實例的。這裡就補齊了前面流程中缺的一塊拼圖。
最後一行通過createRequest方法構建了一個Request來執行測試
這裡的run方法就是構建了基本的測試執行流程,調用了runner對象的run方法來執行具體的測試。前面我們已經梳理了TestRunner的方法的具體流程,這裡就將我們前面梳理的流程完整的串聯起來了。
注意上面的request.getRunner,現在我們只需要梳理出Request是如何獲取到runner的,那麼整個執行流程就完整了。
讓我們回過頭來看createRequest方法。
這裡通過Request的靜態方法classes來構建Request。
這裡構建了一個AllDefaultPossibilitiesBuilder實例,通過builder實例來構建Runner。篇幅限制,我們就直接到AllDefaultPossibilitiesBuilder的runnerForClass方法,來看看builder是怎麼構建Runner的。
首先,構建了5個默認的RunnerBuilder,然後通過對應的RunnerBuilder來構建Runner,如果構建成功了,則直接返回對應的Runner去執行測試。
注意最後一個builder方法junit4Builder,從名字我們可以知道它是用來構建JUnit4Runner的,我們點進去確認一下。
的確是創建JUnit4對象的。
至此,我們整個的執行流程就梳理出來了:
-
JUnitCore根據參數,通過Request和Builder構建了對應的Runner實例
-
Runner通過測試類構建了對應的測試模型,並通過Statement來執行,通過TestNotifier來通知TestListener來處理測試結果
Spring如何整合JUnit
上面的流程和Spring整合JUnit有什麼關係呢?
前面我們知道Spring測試需要添加一個註解RunWith,我們注意上面的builder方法,其中有個builder方法是annotatedBuilder,我們來看這個方法。
此方法通過RunWith註解,找到了對應的類,然後進行了實例化,作為Runner進行返回。注意上面AllDefaultPossibilitiesBuilder的runnerForClass方法的循環,如果找到了Runner就直接返回了,而annotatedBuilder是比較靠前的,所以獲取到Runner後就不會再執行後面的builder了。Spring中就是使用SpringRunner來執行測試了。
而SpringRunner又是如何執行測試的呢?結合前面梳理的Runner流程,你可以自己嘗試去梳理看看。
總結
本文通過Spring如何結合JUnit的例子梳理出了JUnit4完整的執行流程,以及梳理出Spring結合JUnit的方式。通過此方式講述了如何通過關聯延伸閱讀將多個項目整合起來,更好的理解項目之間的關係。
下文將講解不同版本之間源碼的閱讀。