最近需要在團隊中引入單元測試實踐,特地買了《單元測試的藝術》這本書來學習,在單元測試領域這本書寫得相當好,非常系統和完善,對單元測試希望有一個更深入的認識的同學可以找來讀一讀。
這篇文章對UT基礎概念做了一個簡單的總結,下一篇提高篇中再總結一下在Java項目中如何使用PowerMock和Mockito進行測試樁和模擬對象的創建,以規避測試時代碼對外部模塊的依賴問題。
什麼是單元測試
一個單元測試是一段代碼,這段代碼調用一個工作單元,並檢驗該工作單元的最終結果是否與期望的一致。
工作單元可以是一個方法,類或者功能單元。
爲了增強測試代碼的可維護性,我們通常針對用戶更可見的功能單元編寫測試用例。
單元測試具有什麼特性
- 可以被自動化運行
- 很容易實現
- 運行速度很快
- 測試結果是穩定的
- 能完全控制被測試的單元,不包含外部依賴
- 各測試用例相互獨立,無依賴關係
單元測試的價值
- 幫助發現代碼缺陷
- 將缺陷發現的時間提前,開發人員可在本地頻繁運行測試代碼
- 修改或者重構代碼時確保沒有影響現有功能
- 使得開發人員提交代碼更有信心
雖然在一定程度上單元測試增加了需求開發所需的時間,但是單元測試大大提升了代碼的質量和可維護性,使得產品的整體交付週期縮短了。
什麼時候寫單元測試
爲了最大化單元測試的價值,需要引入TDD(測試驅動開發),在產品代碼編寫之前寫單元測試。
TDD流程: 首先編寫一個會失敗的測試,然後編寫產品代碼,接着調試用例確保通過,接下來重構代碼或者創建另一個測試。
怎麼寫單元測試
使用單元測試框架編寫測試代碼,Java項目中推薦使用Junit或者TestNG框架。
一個簡單的單元測試代碼結構如下:
public class AppTest {
@Before
public void setUp() {
// 執行運行前準備工作
}
@After
public void tearDown() {
// 執行運行後銷燬工作
}
@Test
public void unitOfWorkName_Scenario_ExpectedBehavior() {
// 準備階段
// 執行階段
// 驗證階段
}
}
每一個測試用例需要包括準備階段,執行階段和最後的驗證階段。
僞造對象
在編寫測試代碼的過程中會發現,被測代碼通常會與一些不能控制的外部依賴項或者尚未實現的模塊進行交互,我們通常會使用僞造對象來規避依賴項問題。
僞造對象通常包括Stub和Mock,區別如下:
Stub: 測試樁或者存根,在測試時提前定義好接口的請求和響應,作爲僞造的對象使得被測代碼能夠屏蔽掉依賴順利地執行。
Mock: 模擬對象,也是僞造對象,在測試用例中進行斷言時使用,以驗證代碼與其他依賴項之間的交互行爲。
Java項目中推薦使用PowerMock或者JMockit框架進行測試樁和模擬對象的創建。
如何組織和運行單元測試
爲方便管理,測試代碼和產品代碼放在同一個項目中的不同文件夾下,使用Maven工具管理的Java項目產品代碼位於src/main目錄下,單元測試代碼位於src/test目錄下。爲了增強測試代碼的可讀性,每一個測試用例應該與被測工作單元位於同一個package下,每個測試用例的命名規範爲: unitOfWorkName_Scenario_ExpectedBehavior,需要描述清楚被測工作單元,測試場景和期待的行爲。
任何開發或者測試人員可在本地非常快速地運行單元測試代碼。
開發人員在提交代碼之前需要在本地運行單元測試,當所有測試用例通過後才能提交代碼。
單元測試需要集成到CI平臺上,每次構建代碼都需要自動運行單元測試,如果有用例不能通過,需要儘快修復。
參考資料:《單元測試的藝術》