測試驅動javascript開發 — 4.測試驅動開發過程(下)

來源:互聯網
上載者:User
文章目錄
  •   步驟1:編寫測試
  •   步驟2:觀察失敗的測試
  •   步驟3:確保測試通過
  •   步驟4:移除重複的重構
  •   步驟5:重複工作

  TDD是一個迭代的開發過程,他包括下面的步驟:1.編寫測試;2.運行測試,觀察失敗;3.確保測試通過;4.重構,減少重複。

  每次迭代中,測試就是規範。在我們完成開發之後,測試就可以通過了。之後我們就需要進行減少重複代碼和提高設計的重構工作,然後再次運行測試,並保證其通過。

  雖然TDD不主張預期的大設計,但是我們在TDD開始之前還是需要做個簡單的設計。我們要如何寫自己的第一個設計呢?當我們獲得了足夠資訊可以制定測試的時候,測試代碼的編寫,本身就是設計。我們指定在特定情況下特定代碼的行為,系統之間組件如何響應,以及他們之間如何組合。下面我們會舉例,以便大家更好的學習。

  TDD中的迭代時間很短,我們需要非常清楚我們所處的階段。無論何時我們對代碼進行了修改,或者移出了某些功能,我們需要把他們記錄在todo列表中,加以觀察。這個列表可以是一張紙,或者記事本之類的東西,只要方便你快速的尋找和記錄既可。在處理這些新的修改點之前,我們需要首先結束本次迭代。本次迭代結束之後,我們再從todo列表中取出一個任務,開始下一次迭代工作。

 

  步驟1:編寫測試

  每次TDD迭代,首先要做的事情是選擇一個你要做的功能,為它編寫單元測試。單元測試需要簡短,測試聚焦在function上的某一個功能點上。比較好的編寫測試的規則是,編寫盡量少的測試代碼就能讓測試失敗。當然,測試斷言不能和之前的測試重複。如果一個測試涉及到系統的兩個或兩個以上的方面,就說明要麼是這個測試太大了,要麼是裡麵包含了重複的測試點。

  測試需要能夠描述我們實現的功能,我們的功能代碼沒做修改,就不需要修改測試代碼。

  假設我們要完成一個String.prototype.trim函數的開發,用以去除字串前後空格。對該方法好的測試,第一步應該是測試前空格是否刪除了。

testCase("String trim test", {  "test trim should remove leading white-space":  function () {    assert("should remove leading white-space", "a string" === " a string".trim());  }});

  嚴謹起見,我們需要先判斷字串包含trim方法。這是因為我們添加的全域函數可能會和第三方代碼發生衝突,在代碼之前添加 typeof "".trim == "function",可以協助我們在運行測試之前發現問題。

  為單元測試提供輸入條件,運行之後他會判斷輸出條件是否和預期一致。輸入條件不僅僅是函數的參數,任何函數的依賴項,例如全域範圍、某些對象的特殊狀態,這些都是輸入條件。與此類似,輸出結果包括傳回值、全域範圍或者相關對象。我們通常把輸入輸出項分為直接和間接兩種。直接項:函數的參數和傳回值;間接項:不是以參數形式傳入的參數和被修改的外部對象。

 

  步驟2:觀察失敗的測試

  測試準備好之後就可以運行了。有很多原因促使我們在編寫實現代碼之前運行測試,最主要的一點是我們可以用它來確定代碼的狀態。在寫測試的時候,我們會有一個比較明確的期望,測試如何會失敗。單元測試雖然不存在邏輯的分支,代碼也比較簡單,但他也像其他代碼一樣存在bug。但是運行它,比較期望結果,我們會很快發現這些bug。

  理想情況下,當我們添加了新的測試的時候,我們應該可以運行所有測試案例。這樣我們就可以很容易的抓取到幹擾測試,例如一個測試依賴於另外一個測試。

  編寫實現代碼之前運行測試,可以告訴我們一些新的事情。有時候會有這樣的經曆,在我們寫任何實現代碼之前測試可以正常通過。一般情況下,這樣的事情不應該發生,TDD教導我們編寫不能通過的測試。因為我們是先寫測試代碼,功能代碼還沒有開發,這時測試代碼能跑通就說明存在問題。我們需要確定問題的來源,是不是運行環境已經提供了該方法的實現,或者我們有沒有必要保留這條測試案例。

 

  步驟3:確保測試通過

  準備好運行失敗的測試代碼之後,我們要做的就是編寫實現代碼,並保證測試代碼可以運行通過。有時候我們甚至需要寫入程式碼,不必擔心在這個步驟中我們的代碼是多麼糟糕,在後面的重構環節我們可以最佳化他。編寫實現代碼的時候,我們要尋找最明顯的簡潔實現方式,如果沒有我們可以偽造他,而把具體的實現拖延到後面。

  1.你不需要他

  在極限編程中,TDD的精髓是“你不需要他”,意思是直到需要的時候才需要添加相關功能。基於假設添加一些以後可能會用到的代碼,會讓我們的代碼變得很膨脹。對於動態語言,特別是javascript,違反這一原則有時候對我們是有誘惑的,他可以增加代碼的靈活性。一個例子是,為函數添加過多的參數。除非有那樣的需求,否則不要這樣做。

  2.通過String.prototype.trim測試

  下面的代碼是為滿足之前的測試開發的。

String.prototype.trim = function () {  return this.replace(/^\s+/, "");};

  可以看到,這個實現還不完善,只去除了左空格。但是TDD就是這樣的,每一步都很小,只要能讓測試通過就可。發現新的需求點後,編寫測試代碼,然後完善實現代碼並通過測試。

  3.能夠工作的最簡單的方案

  最簡單的解決方案有時候意味著,可能要往產品中添加硬式編碼代碼。因為有時候一般的解決方案可能不是那麼明顯,我們可以用硬式編碼方式推進我們的項目,等到有瞭解決方案的時候再替換。雖然寫入程式碼可以推進我們的項目,代碼品質是我們的最終目標。

  步驟4:移除重複的重構

  最後,最重要也是最有趣的工作就是使代碼變得整潔。當實現代碼開發完畢,測試順利跑通之後,我們就可以考慮重構的工作了,把一些重複的代碼移除。這期間只有一條準則:測試必須能跑通。關於重構好的建議是,每次只對一個操作進行修改,並保證測試能夠通過。重構是對已有代碼的維護修改,所以測試不能失敗。

  重複的代碼可能會出現在不同位置,有時候他是為瞭解決硬式編碼解決方案。如果我們有一個硬式編碼假冒響應,我們需要給他添加另外的測試,讓他在不同輸入的條件下失敗。或許我們一時還想不到替換硬式編碼方案,但至少我們知道問題的存在,他為我們提供了足夠的資訊,方便我們找到最終解決方案。

  重複的代碼同樣可能存在於測試代碼中,例如setup中的請求對象和假冒的依賴。測試代碼也是代碼,同樣需要維護,移除重複內容。如果測試代碼和系統過於耦合,我們需要抽取協助方法和對結構進行重構。setup和teardown可以用來集中設定對象的建立和銷毀。

  我們在重構的過程中不能讓測試失敗。如果在重構的過程中我們沒有用更少的程式碼完成工作,我們就需要考慮把工作托到以後再做。

  步驟5:重複工作

  一旦所有工作都完成了,沒有重複代碼了,也沒有重構工作需要做了,這時候就從todo列表中找一個新任務,重複上面的步驟。根據需要重複這樣的工作。你熟悉了這一過程之後,可以放大腳步,但是確保你的周期很短,這樣可以得到及時的反饋。

  功能滿足需求之後,我們可以考慮提高測試的覆蓋率,可以添加對邊界值的測試、對依賴項的測試、不同輸入類型的測試、不同組件之間的整合測試等。下面是我們為String.prototype.trim添加的第二條測試:

"test trim should remove trailing white-space":function () {  assert("should remove trailing white-space", "a string" === "a string ".trim());}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.