<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 56, comments - 77, trackbacks - 0, articles - 1
      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    敏捷質(zhì)疑: TDD

    Posted on 2008-07-13 21:40 切爾斯基 閱讀(4745) 評(píng)論(4)  編輯  收藏

    Q: 為什么通過單元測(cè)試發(fā)現(xiàn)的 Bug 很少 ?

    A: 單元測(cè)試不是用來(lái)發(fā)現(xiàn) Bug 的, 而是用來(lái)預(yù)防 Bug 的. 如果采用 TDD, 測(cè)試用例完成之時(shí), 產(chǎn)品代碼尚未編寫, Bug更無(wú)從談起.

    Q: 那是否寫單元測(cè)試就能提高代碼質(zhì)量了 ?

    A: 關(guān)于這一點(diǎn), 似乎有人不這么看, <<TDD Opinion: Quality Is a Function of Thought and Reflection, Not Bug Prevention>>. 不錯(cuò), 代碼質(zhì)量并不必然關(guān)聯(lián)到單元測(cè)試, 諸如凈室軟件開發(fā)之類的方法依然可以在沒有單元測(cè)試的情況下得到高質(zhì)量的代碼, 但這是另外一個(gè)問題. 或許主觀上, TDD的本質(zhì)更接近于促使你把質(zhì)量?jī)?nèi)建在思維中, 但客觀上, 在其它條件都相同的情況下, 單元測(cè)試依然能夠起到預(yù)防 Bug 的作用.

    Q: 單元測(cè)試怎么能反映/代替需求 ?

    A: 單元測(cè)試未必能直接反映宏觀上的需求, 但

    1. 功能測(cè)試和集成測(cè)試能夠反映宏觀需求.

    2. 單元測(cè)試能夠反映系統(tǒng)的其它部分對(duì)當(dāng)前單元的需求.

    而從文本的角度, 測(cè)試用例的名字就是需求的描述. 換句話說(shuō), 你從傳統(tǒng)的需求文檔中把描述摳出來(lái), 放到測(cè)試代碼中作為測(cè)試用例的名字, 你便擁有了可執(zhí)行的需求文檔

    一個(gè) RSpec 寫的功能測(cè)試用例 (不要懷疑, 它確實(shí)是可以運(yùn)行的):

      it "should show welcome message after login" do

        login_as_chelsea

        get :index

        response.should have_text(/歡迎 chelsea/)

      end

      it "should not show welcome message after logout" do

        logout

        get :index

        response.should_not have_text(/歡迎/)

      end

    單元測(cè)試的例子:

        public void testShouldBeFreeFrom2amTo5am() throws Exception { //直接業(yè)務(wù)需求

            ...

        }

        public void testShouldThrowExceptionIfCannotFindConfigFile() throws Exception { //來(lái)自系統(tǒng)其它部分的需求

            ...

        }

    測(cè)試用例并不排斥業(yè)務(wù)層面的需求文檔, 一個(gè)高層的, 突出業(yè)務(wù)價(jià)值的需求/愿景描述對(duì)于快速理解系統(tǒng)是非常有幫助的, 但/只是測(cè)試用例以另一種方式描述了真實(shí)的系統(tǒng), 它具有兩個(gè)突出的優(yōu)點(diǎn):

    1. 它不會(huì)說(shuō)謊, 即永遠(yuǎn)與系統(tǒng)真實(shí)的行為同步

    2. 它是可執(zhí)行的, 它可以不知疲倦的, 成本極低的, 時(shí)時(shí)刻刻, 反反復(fù)復(fù)的追問你的系統(tǒng)是否符合需求

    Q: 需求變了怎么辦? 豈不是有大量測(cè)試用例需要修改?

    A: 難道不是應(yīng)該的嗎? 難道以前的需求文檔在需求發(fā)生變化時(shí)不需要修改?  哦, 或許它們不需要, 因?yàn)闆]人會(huì)關(guān)心, 對(duì)代碼也沒什么影響, 需求文檔在度過最初的幾周后便被扔在配置庫(kù)里再也沒人管它了.

    是的, 這關(guān)系到你的測(cè)試策略. 然而通常的測(cè)試策略對(duì)單元測(cè)試的要求都是盡可能周全. 于是這就是一個(gè)測(cè)試設(shè)計(jì)的問題. 是的,測(cè)試代碼也需要設(shè)計(jì), 也需要重構(gòu), 也需要 Domain Specific.

    Q: 我的單元測(cè)試編譯鏈接速度很慢, 而且有些條件很難測(cè), 比如內(nèi)存不足, 或者環(huán)境很難搭建, 比如需要網(wǎng)絡(luò)或數(shù)據(jù)庫(kù), 怎么解決?

    A: 這是集成測(cè)試, 不是單元測(cè)試. 你一定把系統(tǒng)所有的組件都編譯鏈接起來(lái)了. 那么如果你的測(cè)試失敗了, 是哪一部分的問題呢?

    通常單元測(cè)試需要滿足一個(gè)條件: 不依賴任何其它單元, 即隔離性. 實(shí)現(xiàn)手段就是在測(cè)試環(huán)境中能夠輕易的假冒依賴, 并設(shè)定依賴按照我們的意愿進(jìn)行工作. 一個(gè)例子就是你的代碼依賴 malloc 獲取內(nèi)存, 而你想測(cè)試內(nèi)存不足的情況. 那么我們應(yīng)在能夠/需要在單元測(cè)試中使用使用一個(gè)假冒的 malloc 來(lái)代替真正的 malloc, 并且我們能控制假冒的 malloc 返回 NULL 以模擬內(nèi)存不足的情況. 關(guān)于如何做到這一點(diǎn), 可參考一些成熟的"假冒"框架, 如 mockcpp 等.

    Q: 我原來(lái)的測(cè)試都是用真實(shí)的代碼來(lái)跑, 一個(gè)測(cè)試能覆蓋多個(gè)單元. 你現(xiàn)在都把依賴替換掉了, 那被替換掉的模塊有問題怎么辦? 怎么保證集成真實(shí)的代碼后還能正確工作?

    A: 其它單元有其它單元自己的單元測(cè)試, 各自關(guān)注自己. 集成測(cè)試像以前一樣, 該怎么測(cè)還怎么測(cè), 并不是有了單元測(cè)試就不要其它測(cè)試了.

    Q: 單元測(cè)試就是設(shè)計(jì)? 單元測(cè)試怎么能反映/代替設(shè)計(jì) ?

    A: 單元測(cè)試反映的是局部的設(shè)計(jì), 局限于本單元以及與之交互的其它單元. 前面說(shuō)的單元測(cè)試能夠反映系統(tǒng)的其它部分對(duì)當(dāng)前單元的需求, 所謂設(shè)計(jì)就是單元之間的職責(zé)劃分, 交互和依賴關(guān)系

    當(dāng)你試圖測(cè)試一個(gè)單元時(shí), 卻發(fā)現(xiàn)需要?jiǎng)?chuàng)建大量的其它對(duì)象, 而且按照你腦海中的實(shí)現(xiàn), 有些對(duì)象是在單元內(nèi)部創(chuàng)建的, 根本無(wú)法在測(cè)試環(huán)境中假冒它們. 這時(shí)候, 你即使只是為了減少測(cè)試的難度, 也會(huì)逼迫自己思考:

    1. 這個(gè)單元是否做了太多的事, 承擔(dān)了額外的職責(zé), 違反了單一職責(zé)原則?

    2. 是否應(yīng)該把依賴讓外界設(shè)置進(jìn)來(lái), 而不是自己在內(nèi)部創(chuàng)建, 這樣測(cè)試時(shí)就能把依賴設(shè)置為假冒的實(shí)現(xiàn)?

    是的, 單元測(cè)試警示你思考一下自己的設(shè)計(jì)

    Q: 單元測(cè)試是設(shè)計(jì), 還有人說(shuō)源代碼是設(shè)計(jì), 到底是測(cè)試是設(shè)計(jì)還是源代碼是設(shè)計(jì)?

    A: 這實(shí)際上是另外一種角度. 源代碼就是設(shè)計(jì)的論斷基于兩個(gè)假設(shè)

    1. 設(shè)計(jì)階段中工程師的工作產(chǎn)物, 也就是他的設(shè)計(jì), 是應(yīng)該能夠在實(shí)施階段被不同的實(shí)施者嚴(yán)格并且?guī)缀跻荒R粯拥膶?shí)現(xiàn)

    2. 軟件開發(fā)人員也是工程師, 即軟件工程師

    如果我們認(rèn)同這兩個(gè)假設(shè), 那么軟件工程師的什么產(chǎn)物能夠被嚴(yán)格并且重復(fù)實(shí)現(xiàn)的呢? 是你的Word形式的"設(shè)計(jì)"文檔嗎? 是CAD工具畫出的UML圖嗎? 都不是, 因?yàn)樗鼈兌疾痪_, 有無(wú)數(shù)種實(shí)現(xiàn)方式, 根本談不到嚴(yán)格, 不同的開發(fā)人員會(huì)有完全不同的實(shí)現(xiàn). 事實(shí)上, 只有源代碼,才能滿足這個(gè)約束. 這樣軟件的設(shè)計(jì)階段, 就是直到軟件工程師完成源代碼的那一刻, 而軟件的實(shí)施階段, 其實(shí)就只剩編譯和部署了. 跑題了.

    Q: 單元測(cè)試是需求"文檔", 單元測(cè)試又是設(shè)計(jì)"文檔", 它怎么能既是需求又是設(shè)計(jì)呢?

    A: 名字和斷言描述需求, 環(huán)境設(shè)置描述設(shè)計(jì) ...

    Q: 既然單元測(cè)試描述的是需求, 它就應(yīng)該是黑盒測(cè)試了? 可單元測(cè)試不一直都被認(rèn)為是白盒測(cè)試嗎?

    A: 黑白都是相對(duì)于你觀察的層次. 相對(duì)于其它從外部觀察"系統(tǒng)"行為, 不涉及源代碼的測(cè)試來(lái)說(shuō), 單元測(cè)試深入到內(nèi)部觀察盒子的行為, 所以是白盒. 而具體到每個(gè)單元測(cè)試用例, 依然在盡可能的從外部觀察"單元"的行為, 所以又是黑盒.

    Q: 但是你們常用的 Mock 技術(shù), 明顯把單元測(cè)試推向白盒的境地.

    A: 說(shuō)來(lái)話長(zhǎng), 但可以先說(shuō)結(jié)論: 基于狀態(tài)的測(cè)試 over 基于交互/行為的測(cè)試, 雖然右邊的也有巨大的價(jià)值, 但我們認(rèn)為左邊的更穩(wěn)定和更富有對(duì)系統(tǒng)的洞察力

    基于狀態(tài)的測(cè)試描述的是需求, 基于交互行為的測(cè)試描述的是實(shí)現(xiàn). 相對(duì)于需求來(lái)說(shuō), 實(shí)現(xiàn)更易發(fā)生變化, 尤其在另外一種實(shí)踐"重構(gòu)"的沖擊下, 描述實(shí)現(xiàn)的測(cè)試將被修改的面目全非, 帶來(lái)相當(dāng)?shù)姆倒ず途S護(hù)成本

    一種例外, 就是交互本身就是需求, 這時(shí) mock 是合適的選擇. 一個(gè)杜撰的例子參見<<TDD: Tricky Driven Design 3, 方法>>中最后銀行API的例子

    而現(xiàn)實(shí)生活中, 存在一些情況, 雖然使用 mock 可能帶來(lái)后期的維護(hù)成本, 但它帶來(lái)的好處也是不可代替的. 比如對(duì)先期整體測(cè)試代碼的編碼量的降低. 這在 C/C++ 項(xiàng)目中尤其明顯:

    受限于C/C++的編譯模型, 使用常用的預(yù)處理期接入點(diǎn)和編譯鏈接接入點(diǎn)技術(shù)來(lái)接入 stub 實(shí)現(xiàn)時(shí), 要小心維護(hù)頭文件的防衛(wèi)宏, 頭文件的名稱, 不同環(huán)境下構(gòu)建腳本的include路徑設(shè)置, 庫(kù)路徑設(shè)置等. 手工寫stub的方式變的及其繁瑣和容易出錯(cuò). 這時(shí)候, 一個(gè)易用的 mock 框架如 mockcpp 等將節(jié)省大量的編碼和先期維護(hù)工作

    而幾乎所有的mock框架, 都支持將 mock 對(duì)象退化為 stub, 如 mockcpp 中 mock 對(duì)象的 defaults() 設(shè)置, 或者 JMock 2 中的 Allowing . 事實(shí)上, 這是我推薦的 mock 使用方式: 通常情況下讓它退化為簡(jiǎn)單的stub, 必要時(shí)才使用它強(qiáng)大的期待設(shè)置和驗(yàn)證能力.

    通常單元測(cè)試有兩個(gè)公認(rèn)的約束需要滿足:

    1. 隔離依賴.

    重申一遍結(jié)論就是: 在滿足單元測(cè)試的快和隔離依賴的前提下,

    1. 優(yōu)先選擇基于狀態(tài)的黑盒測(cè)試(可使用手寫stub或mock退化的stub)

    2. 除非交互和行為本身就是需求(可使用mock對(duì)象的全部特性)

    Q: 怎么測(cè) private 函數(shù)?

    A: 把它變成 public 的.

    我是認(rèn)真的. 如果發(fā)現(xiàn) private 函數(shù)無(wú)法簡(jiǎn)單的通過某個(gè)public函數(shù)的測(cè)試來(lái)覆蓋而需要專門的測(cè)試, 意味著你的單元可能承擔(dān)了太多的職責(zé), 應(yīng)該拆分到一個(gè)單獨(dú)的單元中, 并開放為 public 函數(shù).

    如果使用 C++, 在測(cè)試環(huán)境中 #define private public.

    如果使用 g++, 在測(cè)試環(huán)境中加入 -fno-access-control.

    Q: 類似 private, 一些意圖實(shí)現(xiàn)良好設(shè)計(jì)的語(yǔ)言特性, 如 static, sealed, final, 非虛函數(shù)等, 卻總是給代碼的易測(cè)試性帶來(lái)麻煩, 該如何取舍?

    A: 沒什么好辦法. 這些語(yǔ)言特性和測(cè)試的目的是相同的, 都是為提高代碼質(zhì)量, 減少出錯(cuò)的可能, 雖殊途同歸, 但卻互相限制, 效果也不一樣.

    我認(rèn)為工業(yè)界是時(shí)候嚴(yán)肅認(rèn)真的考慮測(cè)試環(huán)境了, 最好在語(yǔ)言中內(nèi)建對(duì)測(cè)試的支持, 一些為產(chǎn)品環(huán)境設(shè)計(jì)的語(yǔ)言特性, 應(yīng)該在測(cè)試環(huán)境中關(guān)閉, 而在產(chǎn)品環(huán)境中生效. 其實(shí)之前很多編譯器都支持 Release 和 Debug 兩種環(huán)境, 也是從代碼質(zhì)量的方面考慮的. 現(xiàn)在毫無(wú)疑問證實(shí)單元測(cè)試比 Debug 更有效, 是時(shí)候與時(shí)俱進(jìn)增加對(duì) Test 的支持而逐漸罷黜對(duì) Debug 的支持.

    在語(yǔ)言本身增加對(duì)測(cè)試的支持之前, 我們不得不想辦法在測(cè)試環(huán)境中繞過語(yǔ)言特性的限制, 尤其對(duì)遺留系統(tǒng), 代碼已經(jīng)存在的情況. 比如對(duì)于 C++ 中的 static 函數(shù), 可以將整個(gè)被測(cè)單元 #include, 或者 #define static 為空. 宏代表了一層間接, 在測(cè)試環(huán)境中, 這層間接是至關(guān)重要的. 其它方法可參考 <<Working Effectively with Legacy Code>>, <<假冒的藝術(shù)>>中的介紹.

    Q: 剛才提到了要支持"測(cè)試"而不是"Debug", 測(cè)試和Debug難道有什么矛盾嗎?

    A: 有. 如果你發(fā)現(xiàn)不得不 Debug, 就是測(cè)試粒度太粗, 步子邁的太大, 產(chǎn)品代碼過長(zhǎng)等導(dǎo)致的, 甚至可能你卷入了過多的單元而破壞了測(cè)試的隔離性. Debug還是代碼邏輯不清, 行為難以斷言的表現(xiàn).  用測(cè)試幫你定位錯(cuò)誤.

    Q: 我知道為遺留系統(tǒng)增加新特性是要先寫測(cè)試保證系統(tǒng)原來(lái)的行為, 可遺留代碼很龐大, 我甚至都不知道系統(tǒng)目前的行為, 怎么辦?

    A: 特征測(cè)試: 保持代碼行為的測(cè)試, 獲取當(dāng)前運(yùn)行結(jié)果, 來(lái)填充測(cè)試, 以獲取系統(tǒng)目前行為. 其實(shí)測(cè)試可以分為兩類: 試圖說(shuō)明想要實(shí)現(xiàn)的目標(biāo), 或者試圖保持代碼中既有的行為; 在特性實(shí)現(xiàn)后, 前者會(huì)轉(zhuǎn)化為后者. 詳細(xì)信息請(qǐng)參見<<Working Effectively with Legacy Code>>

    Q: 有成熟的關(guān)于在遺留系統(tǒng)上實(shí)踐 TDD 或者單元測(cè)試的實(shí)踐嗎?

    A: 還是<<Working Effectively with Legacy Code>>, 或者<<在大型遺留系統(tǒng)基礎(chǔ)上運(yùn)作重構(gòu)項(xiàng)目>>

    Q: 前面經(jīng)常說(shuō)到 C++ 或其它面向?qū)ο笳Z(yǔ)言, 卻沒有提到 C, 那么過程式語(yǔ)言中如何應(yīng)用 TDD ? 有什么不一樣?

    A: 基本一樣, 并且在過程式語(yǔ)言中應(yīng)用 TDD, 可能會(huì)導(dǎo)出面向?qū)ο箫L(fēng)格的設(shè)計(jì). 比如如果直接調(diào)用某個(gè)函數(shù), 那么不得不通過編譯時(shí)替換或鏈接時(shí)替換來(lái)接入假的實(shí)現(xiàn). 這樣其實(shí)比較麻煩, 因此可能會(huì)促使你選用函數(shù)指針 ,以便方便的在測(cè)試環(huán)境中進(jìn)行替換. 隨著時(shí)間的推移, 你會(huì)發(fā)現(xiàn)一組組概念相關(guān)的函數(shù)指針出現(xiàn)了, 那么把它們和它們操作的數(shù)據(jù)綁定在一起, 定義一個(gè) struct, 就形成了一種對(duì)象風(fēng)格. 當(dāng)然這反而可能會(huì)令你的代碼更復(fù)雜, 這需要在實(shí)踐中取舍.

    也有可能在過程式語(yǔ)言中你覺得 TDD 對(duì)設(shè)計(jì)的促進(jìn)不大, 而且測(cè)試用例也比較枯燥, 就是測(cè)個(gè)分支, 返回值什么的. 是的, 邏輯就隱藏在分支和返回值中, 如果習(xí)慣了過程式思維并不打算改變, TDD 對(duì)設(shè)計(jì)的影響則更多的體現(xiàn)在依賴管理上, 如頭文件和編譯單元的職責(zé)劃分. 如果把不同職責(zé)的函數(shù)混在一個(gè)編譯單元里面, 則很難實(shí)施鏈接替換等手段, 除非你選擇一個(gè)類似 mockcpp 的框架, 不需要鏈接替換.

    Q: 如果使用 TDD, 那么測(cè)試人員怎么安排? 是不是一開始就要進(jìn)入項(xiàng)目組? 可那時(shí)還沒有產(chǎn)品代碼,測(cè)什么?

    A: 是, 是一開始就要進(jìn)入項(xiàng)目組, 可不是因?yàn)?TDD.  是, 測(cè)試人員是一開始沒什么可測(cè)的, 可不代表就沒活干.

    TDD是一種開發(fā)方法, 是開發(fā)人員參與的活動(dòng). 其效果是以可執(zhí)行的形式文檔化你的需求, 迫使你分清職責(zé)隔離依賴以驅(qū)動(dòng)你的設(shè)計(jì), 編織安全網(wǎng)以扼殺Bug在搖籃狀態(tài)防止逃逸. 可傳統(tǒng)測(cè)試人員的活動(dòng)是試圖找到已經(jīng)逃逸的Bug. 這兩種活動(dòng)都是必要的, 而且毫不沖突, 互為補(bǔ)充.

    那么測(cè)試人員在新的特性還沒開發(fā)完成之前做什么呢? 除了提前寫測(cè)試用例, 無(wú)論是自動(dòng)化的還是非自動(dòng)化的, 而需要測(cè)試人員參加的一項(xiàng)重要活動(dòng), 就是參與特性驗(yàn)收條件的制定. 之前經(jīng)常發(fā)生開發(fā)人員按照自己的理解去編碼, 測(cè)試人員按照自己的理解去測(cè)試, 直到開發(fā)完成, 測(cè)試過程中才發(fā)現(xiàn)理解的不一致, 開始產(chǎn)生爭(zhēng)執(zhí)并阻塞等待業(yè)務(wù)分析人員(如果幸運(yùn)的話)或者行政主管(如果開發(fā)過程混亂的話)的仲裁. 解決辦法就是就在開始開發(fā)新特性前的一剎那, 由業(yè)務(wù)分析人員, 測(cè)試人員, 開發(fā)人員進(jìn)行一次討論, 就驗(yàn)收條件達(dá)成一致并形成記錄, 然后測(cè)試人員和開發(fā)人員分頭去寫測(cè)試和實(shí)現(xiàn).

    Q: 之前會(huì)有一個(gè)階段, 就是一組相關(guān)的特性開發(fā)完成后, 測(cè)試人員接手測(cè)試, 幾輪Bug修復(fù)過去后, 產(chǎn)品基本穩(wěn)定就可以發(fā)布了. 現(xiàn)在測(cè)試人員提前介入到每個(gè)迭代中, 針對(duì)單個(gè)特性進(jìn)行測(cè)試, 那如何保證產(chǎn)品集成起來(lái)的質(zhì)量?

    A: 跟以前一樣, 該有那么個(gè)集成測(cè)試階段還得有那么個(gè)集成測(cè)試階段, 取決于產(chǎn)品當(dāng)時(shí)的質(zhì)量狀態(tài). 并不是說(shuō)有了迭代級(jí)別, 單個(gè)特性級(jí)別的測(cè)試就不需要發(fā)布級(jí)別的集成測(cè)試了, 兩者沒有任何矛盾.

    Q: 那么測(cè)試人員提前進(jìn)入迭代有什么好處?

    A: 盡早發(fā)現(xiàn)問題, 降低修復(fù)錯(cuò)誤的成本. 有幾種手段, 一是前面提到與業(yè)務(wù)人員和開發(fā)者一起討論驗(yàn)收條件, 這樣就能防止理解偏差而導(dǎo)致的返工. 二是開發(fā)完成立即測(cè)試, 發(fā)現(xiàn)問題立即反饋, 這樣開發(fā)人員對(duì)代碼依然印象深刻,能快速定位和修復(fù)錯(cuò)誤. 這樣流入最后集成測(cè)試階段的Bug就會(huì)少, 會(huì)縮短最后的集成測(cè)試時(shí)間, 保證產(chǎn)品更平穩(wěn)的發(fā)布.

    Q: 有時(shí)候后續(xù)的特性會(huì)影響前面的特性, 那么迭代過程中測(cè)試人員只測(cè)單個(gè)特性, 怎么保證以前的特性依然工作?

    A: 幾個(gè)手段. 測(cè)試盡量自動(dòng)化, 以便能夠持續(xù)集成. 再就是做好依賴管理, 每當(dāng)一個(gè)新特性完成, 就應(yīng)該能夠發(fā)現(xiàn)它影響的其它特性, 看看是否應(yīng)該補(bǔ)充一些集成測(cè)試.

    Q: 有時(shí)候開發(fā)人員完成一個(gè)特性時(shí)已接近迭代結(jié)束, 測(cè)試人員沒有時(shí)間進(jìn)行充分測(cè)試, 怎么辦?

    A: 下個(gè)迭代測(cè)唄, 并且在計(jì)算開發(fā)速度時(shí), 只應(yīng)該計(jì)算本迭代通過測(cè)試人員驗(yàn)收的特性, 那些僅僅是開發(fā)人員完成, 沒有經(jīng)過測(cè)試人員充分測(cè)試的特性不計(jì)在內(nèi). 這種情況是不可避免的. 但我們能通過一些手段讓測(cè)試與開發(fā)更加同步, 盡量縮短滯后性, 包括讓測(cè)試人員與開發(fā)人員更緊密合作, 盡量讓測(cè)試用例自動(dòng)化等.

    Q: 我還是覺得在開發(fā)迭代過程中, 測(cè)試人員的工作量不飽滿.

    A: 如果這不是您的感覺, 而是事實(shí), 并且前面測(cè)試人員必須要做的工作也都做了, 還是不飽滿, 那么恭喜你, 可以省下一些測(cè)試人員, 去做別的事了. 但不推薦的是, 不要讓測(cè)試人員同時(shí)為兩個(gè)團(tuán)隊(duì)工作. 這會(huì)大大增加溝通的成本. 你會(huì)經(jīng)常發(fā)現(xiàn), 當(dāng)你的開發(fā)者想找測(cè)試人員協(xié)助時(shí), 卻找不到人了, 于是你的團(tuán)隊(duì)便被堵塞在那里. 而測(cè)試人員本身的Context切換也是痛苦的.

    Q: 你們說(shuō)驗(yàn)收測(cè)試應(yīng)該由客戶來(lái)編寫, 可在我們這里根本不可能.

    A: 驗(yàn)收, 當(dāng)然是由客戶來(lái)驗(yàn)收, 這在理論上是毫無(wú)疑問的, 而且肯定在各行各業(yè)發(fā)生著. 只是具體到測(cè)試用例的編寫和執(zhí)行, 無(wú)論是自動(dòng)化的還是非自動(dòng)化的, 都需要掌握一定的技術(shù), 需要周密的思考, 需要專門的時(shí)間, 客戶可能無(wú)法同時(shí)滿足這幾個(gè)條件, 我們要盡力爭(zhēng)取, 爭(zhēng)取不到, 便只好通過更充分的交流來(lái)彌補(bǔ)越俎代庖的失真. 這時(shí)業(yè)務(wù)分析人員和測(cè)試人員要通力合作, 完成驗(yàn)收測(cè)試的編寫.

    Q: 你們說(shuō)你們之前的項(xiàng)目產(chǎn)品代碼和測(cè)試代碼的比例大約 1:3, 這不是平白增加了 3 倍的工作量嗎?

    A: 是增加了 3 倍的代碼量而不是工作量. 它節(jié)省了你幾十人做幾個(gè)月龐大的預(yù)先設(shè)計(jì)的工作量, 節(jié)省了你詳細(xì)設(shè)計(jì)每個(gè)模塊并為之編寫幾百頁(yè)詳設(shè)文檔的時(shí)間, 節(jié)省了無(wú)數(shù)不眠之夜通宵Debug的時(shí)間, 它節(jié)省了集成階段修復(fù)難以計(jì)數(shù)的Bug的工作量, 甚至它縮減了你產(chǎn)品代碼的數(shù)量, 大量的重復(fù)代碼被消除了, 大量過度設(shè)計(jì)的復(fù)雜代碼被廢除了, 你的代碼更易理解了, 添加新特性更容易了, 發(fā)現(xiàn)的Bug更易定位了, 以致于大大減少了長(zhǎng)達(dá)數(shù)年的生命周期內(nèi)維護(hù)的工作量. 有點(diǎn)夸張了? 可這就是 TDD 和敏捷開發(fā)帶給我們的好處(如果你已經(jīng)實(shí)踐了)和vision(如果你還在觀望)

    Q: 我們也做單元測(cè)試, 但是是先寫產(chǎn)品代碼后寫測(cè)試的. 難道非得 TDD, 非得測(cè)試先行嗎?

    A: 沒什么事是非做不可的. 取決于你要什么. TDD 只是以可驗(yàn)證的方式迫使你將質(zhì)量?jī)?nèi)建在思維中, 長(zhǎng)期的測(cè)試先行將歷練你思維的質(zhì)量. 而事后的單元測(cè)試只是惶恐的跟隨者.


    評(píng)論

    # re: 敏捷質(zhì)疑: TDD  回復(fù)  更多評(píng)論   

    2008-08-20 15:48 by rocket
    應(yīng)該再加一個(gè):
    Q:UT是測(cè)試接口還是測(cè)試實(shí)現(xiàn)?
    A:UT測(cè)試的是代碼,是為了讓代碼正確的工作,所以你要測(cè)試接口的話,那就必須要接口里可以寫代碼:)

    # re: 敏捷質(zhì)疑: TDD  回復(fù)  更多評(píng)論   

    2008-09-18 18:12 by sp123馬甲
    加了這個(gè)就必須再加一個(gè):
    Q: 是否先寫實(shí)現(xiàn)代碼然后寫測(cè)試代碼?
    A: 不是這是基本的TDD概念問題哦!測(cè)試先行,測(cè)試的整個(gè)流程都可以針對(duì)接口,只有第一句實(shí)例化被測(cè)試對(duì)象時(shí)才需要針對(duì)實(shí)際的實(shí)現(xiàn)。即使如此,測(cè)試寫下來(lái)之后,你無(wú)法編譯通過,這正好是TDD的第一個(gè)動(dòng)作,你需要補(bǔ)充一個(gè)實(shí)現(xiàn)來(lái)讓編譯通過!

    # re: 敏捷質(zhì)疑: TDD  回復(fù)  更多評(píng)論   

    2008-12-18 21:12 by lilee
    寫的很好,可否轉(zhuǎn)載?

    # re: 敏捷質(zhì)疑: TDD  回復(fù)  更多評(píng)論   

    2008-12-18 21:25 by chelsea
    @lilee

    注明出處就可以.

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲国产成人AV网站| 成年性生交大片免费看| 国产精品亚洲专区无码WEB| 久久亚洲国产成人精品性色| 国产一级淫片视频免费看| 国产1000部成人免费视频| 中文字幕看片在线a免费| 亚洲va中文字幕| 最新亚洲卡一卡二卡三新区| 亚洲男人天堂2017| 国产偷国产偷亚洲高清日韩| 永久免费毛片手机版在线看| 青苹果乐园免费高清在线| 99视频免费观看| 久久精品视频免费播放| 91国内免费在线视频| 成年大片免费视频播放一级| 亚洲av无码片vr一区二区三区 | 日韩亚洲翔田千里在线| 一本天堂ⅴ无码亚洲道久久| 亚洲福利视频网站| 精品亚洲aⅴ在线观看| 亚洲国产综合专区电影在线| 亚洲AV无码一区东京热久久 | 四虎精品免费永久免费视频| 亚洲精品第一国产综合亚AV| 亚洲中文字幕无码中文| 四虎亚洲精品高清在线观看| 亚洲午夜精品一区二区公牛电影院| 亚洲福利一区二区三区| 亚洲精品视频在线播放| 亚洲国产高清美女在线观看| 亚洲欧洲日产专区| 亚洲一级视频在线观看| 亚洲最大成人网色香蕉| 亚洲va久久久久| 亚洲精品无码av片| 国产精品亚洲一区二区三区| 男人和女人高潮免费网站| 一级毛片在线免费播放| 你是我的城池营垒免费看 |