從單元測試覆蓋率看富領域模型到底有多富
使用了DDD(領域驅動設計)後,代碼有什麼不同呢?這多是程序員們在接觸DDD後最關心的一個問題。這個系列文章會對一些優秀的DDD實例代碼進行分析,管中窺豹,略見數斑。這是第一篇。git
DDD中程序員最關心的部分
DDD(領域驅動設計)是一個複雜而全面的方法,編碼只是最後一步。 程序員
https://github.com/ddd-crew/ddd-starter-modelling-processgithub
但這是程序員最關心的部分,也是被問到最多的問題。 因此計劃寫個系列文章對一些優秀的DDD實例代碼進行分析,但願能解開一些困惑。數據庫
IDDD(《實現領域驅動設計》),是最常被推薦的一本書。書中有一個關於構建Scrum管理軟件的例子,咱們先來分析這個經典的例子的源碼(https://github.com/VaughnVernon/IDDD_Samples)。api
第一篇先從單元測試和富領域模型提及。工具
我所目擊單元測試之怪狀
關於自動化的單元測試,無數人都心懷嚮往。單元測試
《The Clean Coder》裏邊描述的測試金字塔給出了單元測試在整個測試中的位置。學習
經是好經,但大部分時候會被歪嘴和尚給念歪:測試
- 我遇到的第一個例子,比較廣泛,開發人員用JUnit寫單元測試,每次本地開發的時候改一改,當main方法用,在構建的時候都把test case都給skip掉
- 我遇到的第二個例子,是曾經有一個質量效能部門推進對單測覆蓋率進行考覈。結果各個開發團隊有苦難言,只有一個開發團隊作的比較好,質量效能團隊給發了個大獎,後來有人發現這個團隊的測試覆蓋率高,是由於他們寫了一個代碼自動生成工具,給每一個get/set方法都生成了JUnit測試……質量效能團隊被piapia打臉
- 我遇到的第三個例子,是一個 有追求的團隊,他們在構建時不skip,但每次作需求的時候,修改單元測試代碼的時間甚至會超過了編寫正式代碼的時間
- 我遇到的第四個例子,是一個更有追求的團隊,他們想學習Google、Facebook搞主幹開發模式,把CI/CD作的特別好,但自動化測試覆蓋率不夠還常常跑不通,沒有了自動化測試作保障,主幹開發也不得不做罷
我在《當咱們在談論單測時咱們在談論什麼》裏分析過這個問題: 「自動化單元測試 = 自動化 + 單元 + 測試」,本質緣由是大部分代碼「單元化」程度很低,因此,這個前提不具有,是折騰不成功的。編碼
但DDD的富領域模型有助於達成這個前提。
富領域模型爲何有助於單測
DDD的代碼組織推薦六邊形模型,一個重點是領域層和應用層的分工。
這裏有幾個有助於用低成本(編寫和維護)提高覆蓋測試率的條件:
- 領域層裏的實體對象再也不只是有get/set方法,還有不少業務邏輯。
- 領域實體是沒有任何外部依賴的,也就是說,這些業務邏輯都是本地內存中就能夠執行的
- 以聚合組織的領域實體內聚性強
- 從圖上也能夠看出,應用層比較薄,領域層比較厚
咱們看看IDDD_Sample這麼作了之後,單元測試覆蓋率的達到理想的情況嗎?
IDDD示例的單測覆蓋率統計
首先咱們選擇agilepm這個模塊,看看應用層代碼行數和領域層代碼行數的對比,看看是否符合領域層比較厚的這個前提。
領域層代碼6943行,而應用層只有750行,領域層代碼佔比達到了90%!!!這個比例是否是和咱們平時寫的貧血模型代碼很不同?
下面咱們看看領域層的無任何外部依賴的單元測試(不須要Mock,不須要準備數據庫等)的測試覆蓋率:
行代碼覆蓋率有70%!!!我看了一下,這其中沒有被測試到的,是一些equals、get/set方法。除去這些,應該會達到90%,或者繼續作的100%也並不難。
總結起來,這個應用的90%的邏輯能夠有90%的自動化單元測試覆蓋率 —— 不須要mock,不須要依賴數據庫、外部中間件、RPC等。
這得益於它使用了富領域模型,而不是貧血模型,得益於其正確地組織了業務邏輯代碼。測試覆蓋率也從側面展現了富領域模型到底有多富。
可是先不要急
我最擔憂的是有人看到這裏說:懂了,咱們開始搞富領域模型吧!
這可能讓你從一個坑裏爬出來,接着跳到另一個坑裏。
自動化單測難以推行,是由於「單元化」這個前提不具有。富領域模型能夠幫助這個前提的達成。
但富領域模型的前提是什麼?已經具有了嗎?
且待下回分解。