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