本書講解如何用單元測試引領(lǐng)開發(fā)工作, 以解決業(yè)務(wù)領(lǐng)域中的復(fù)雜問題。本書把需求劃分成多個比較小的功能, 并分別予以實(shí)現(xiàn)。無論采用哪種編程語言與編程框架, 你都可以把書里的知識運(yùn)用到日常的編程工作之中。本書包含下列內(nèi)容: 用 TDD 把業(yè)務(wù)領(lǐng)域中的復(fù)雜問題劃分成多個小的功能, 并分別予以實(shí)現(xiàn); 如何在各種編程語言里面, 用各種測試框架來做測試驅(qū)動開發(fā) (TDD)。
本書采用一個完整的項(xiàng)目貫穿各章,作者全程示范了如何把項(xiàng)目拆解成多個小功能,并依次采用測試驅(qū)動的方式實(shí)現(xiàn)這些功能。每實(shí)現(xiàn)一個功能,作者都會演示如何通過重構(gòu),把這個功能的代碼乃至項(xiàng)目的結(jié)構(gòu)調(diào)整得更好。作者采用三種編程語言講解,這不僅能吸引更多的人來閱讀,而且讓我們能夠觀察各種編程語言在設(shè)計思路與實(shí)現(xiàn)細(xì)節(jié)方面的異同,進(jìn)而養(yǎng)成一種超越編程語言的設(shè)計思維。大家在書中會看到如何結(jié)合具體語言的優(yōu)勢,以清晰的代碼將這種思維表達(dá)出來。此外,作者還指引我們把這個項(xiàng)目提交到本地的 git 代碼庫中,以便做版本管理,并且告訴我們?nèi)绾螌⒈镜貍}庫與遠(yuǎn)程的 GitHub 庫同步,以及如何通過腳本制作 CI(持續(xù)集成)管道,讓項(xiàng)目代碼每次推送到遠(yuǎn)程庫之后都能夠自動接受測試。
測試驅(qū)動開發(fā)(Test-Driven Development,TDD)這種編程手法或許很早就出現(xiàn)了,它后來能夠重新得到關(guān)注的其中一個原因在于,有一群開發(fā)者很樂意通過各種實(shí)例向我們介紹該手法的好處。我剛學(xué)編程的那幾年,依然在用老辦法寫程序,雖然也做過一些測試,但都是實(shí)現(xiàn)完功能之后補(bǔ)寫的,直到 2007 年看了 Kent Beck 的《測試驅(qū)動開發(fā)》(Test-Driven Development: By Example),才發(fā)現(xiàn)原來程序可以這樣寫。
從最基本的流程上說,TDD 可以概括成三個環(huán)節(jié):首先,寫一項(xiàng)測試,以描述有待實(shí)現(xiàn)的某個功能,并在其中做出斷言,以表示產(chǎn)品的執(zhí)行效果必定與期望的效果相符,由于我們還沒有編寫相關(guān)的產(chǎn)品代碼,因此這樣的測試幾乎總是無法通過;其次,用極其簡單的方式(甚至可以是硬代碼)來編寫產(chǎn)品,讓這項(xiàng)測試能夠通過;最后,重構(gòu)產(chǎn)品與測試代碼,讓兩者都變得更加準(zhǔn)確、清晰。
測試代碼明確地描述了需求,促使開發(fā)者必須寫出滿足該需求的產(chǎn)品代碼,這確保我們不會走錯方向。測試越寫越多,這些測試所覆蓋的范圍也逐漸擴(kuò)大,這促使我們把代碼寫得越來越通用,但是,由于我們在每一輪迭代時都力求用最簡單的寫法讓測試通過,因此不會像以前那樣總是想一下子就寫出極為通用的代碼,從而導(dǎo)致過度設(shè)計。另外,有這套測試做保障,就不用害怕新編的代碼會破壞已經(jīng)寫好的功能了,因?yàn)榧偃绯霈F(xiàn)那樣的情況,就會有測試無法通過,從而提醒我們注意該問題。
現(xiàn)在距離《測試驅(qū)動開發(fā)》一書面世已經(jīng)20多年了,但仍有一些朋友尚未嘗試過TDD,還有一些雖然嘗試過,但尚未完全了解它的理念并體會到它的好處。如果說 Kent Beck 重新發(fā)現(xiàn)了 TDD,那么 Saleem Siddiqui 的這本書則有可能讓 TDD 變得更加流行。
本書采用一個完整的項(xiàng)目貫穿各章,作者全程示范了如何把項(xiàng)目拆解成多個小功能,并依次采用測試驅(qū)動的方式實(shí)現(xiàn)這些功能。每實(shí)現(xiàn)一個功能,作者都會演示如何通過重構(gòu),把這個功能的代碼乃至項(xiàng)目的結(jié)構(gòu)調(diào)整得更好。作者采用三種編程語言講解,這不僅能吸引更多的人來閱讀,而且讓我們能夠觀察各種編程語言在設(shè)計思路與實(shí)現(xiàn)細(xì)節(jié)方面的異同,進(jìn)而養(yǎng)成一種超越編程語言的設(shè)計思維。大家在書中會看到如何結(jié)合具體語言的優(yōu)勢,以清晰的代碼將這種思維表達(dá)出來。此外,作者還指引我們把這個項(xiàng)目提交到本地的 git 代碼庫中,以便做版本管理,并且告訴我們?nèi)绾螌⒈镜貍}庫與遠(yuǎn)程的 GitHub 庫同步,以及如何通過腳本制作 CI(持續(xù)集成)管道,讓項(xiàng)目代碼每次推送到遠(yuǎn)程庫之后都能夠自動接受測試。
總之,這是一本流暢而連貫的教程,能讓大家很快喜歡上TDD。當(dāng)然,TDD 本身仍有一些地方尚待思考,例如怎樣測試圖形界面以及多線程的代碼等,希望大家結(jié)合自己的實(shí)際工作來探索這些問題。
Saleem Siddiqui是一位軟件開發(fā)者,他也參與培訓(xùn)、演講和寫作。他具有豐富的技術(shù)開發(fā)經(jīng)驗(yàn),在大大小小的團(tuán)隊(duì)中開發(fā)過醫(yī)療、零售、政務(wù)、財務(wù)以及制藥等方面的軟件。Saleem將在本書中分享自己過去的經(jīng)驗(yàn)與教訓(xùn),幫助大家避開他以前編寫軟件時犯的錯誤。
第0章 簡述如何配置開發(fā)環(huán)境21
0.1 配置開發(fā)環(huán)境21
0.2 小結(jié)28
第一部分 入門
第1章 我們要解決的問題:Money31
1.1 TDD 的基本流程:紅-綠-重構(gòu)循環(huán)31
1.2 我們要解決的是什么問題32
1.3 第一個失敗的測試33
1.4 讓測試通過37
1.5 清理代碼41
1.6 提交變更44
1.7 小結(jié)45
第2章 通過Money實(shí)體支持多種貨幣48
2.1 開始支持歐元48
2.2 讓代碼遵循DRY原則50
2.3 剛才不是說要遵循 DRY 原則嗎?現(xiàn)在為什么要保留兩個相似的測試52
2.4 分而治之(實(shí)現(xiàn)除法)53
2.5 清理代碼57
2.6 提交變更60
2.7 小結(jié)60
第3章 通過Portfolio實(shí)體支持投資組合62
3.1 設(shè)計下一個測試62
3.2 提交變更71
3.3 小結(jié)71
第二部分 模塊化
第4章 關(guān)注點(diǎn)分離75
4.1 測試代碼與產(chǎn)品代碼75
4.2 模塊化78
4.3 去除冗余(消除重復(fù))79
4.4 小結(jié)80
第5章 Go語言的包與模塊81
5.1 把代碼分割到不同的包中81
5.2 Go 語言的模塊82
5.3 創(chuàng)建新包84
5.4 封裝86
5.5 消除測試中的重復(fù)88
5.6 提交變更88
5.7 小結(jié)88
第6章 JavaScript的模塊90
6.1 把代碼劃分成多個模塊90
6.2 認(rèn)識 JavaScript 模塊92
6.3 改進(jìn)測試96
6.4 提交變更104
6.5 小結(jié)105
第7章 Python的模塊106
7.1 把代碼劃分成多個模塊106
7.2 消除測試中的重復(fù)108
7.3 提交變更108
7.4 小結(jié)108
第三部分 功能與重新設(shè)計
第8章 求Portfolio的值111
8.1 處理幣種不同的Money111
8.2 提交變更119
8.3 小結(jié)119
第9章 這種錢,那種錢120
9.1 制作映射表以便查詢匯率120
9.2 提交變更127
9.3 小結(jié)128
第10章 錯誤處理129
10.1 我們想把錯誤處理機(jī)制實(shí)現(xiàn)成什么樣子129
10.2 提交變更141
10.3 小結(jié)142
第11章 通過Bank實(shí)體重新設(shè)計143
11.1 依賴注入144
11.2 把所有實(shí)體匯聚起來145
11.3 提交變更166
11.4 小結(jié)166
第四部分 收尾
第12章 掌握測試順序171
12.1 修改匯率172
12.2 提交變更180
12.3 小結(jié)181
第13章 持續(xù)集成182
13.1 核心概念183
13.2 把實(shí)現(xiàn)持續(xù)集成所需的步驟串起來187
13.3 提交變更198
13.4 小結(jié)203
第14章 回顧204
14.1 代碼是否具備良好的形象205
14.2 代碼是否確切地實(shí)現(xiàn)了目標(biāo)208
14.3 在編寫代碼的過程中有沒有其他路可走210
14.4 從三個維度分析代碼211
14.5 TDD 過時了嗎224
14.6 全書總結(jié)226
附錄 A 配置開發(fā)環(huán)境227
附錄B 三種語言簡史237
附錄C 致謝244