2018年10月16日 星期二

《面試官別再問》行為驅動BDD / 測試驅動TDD 軟體開發模式

行為驅動開發(BDD)Behavior-Driven Development

定義


這種開發模式也可以看作是對TDD 的一種補充,它鼓勵軟件項目中的開發人員,測試人員和非技術人員或者客戶之間的協作,從用戶的需求出發,強調系統行為。在TDD 中,我們並不能完全保證根據設計所編寫的測試就是用戶所期望的功能,用戶並一定能看懂測試用例。 BDD 將這一部分用更接近自然語言的形式來描述,讓測試用例更自然化和簡單,使開發人員,測試人員和客戶能在這個基礎上達成一致。

TDD 與BDD 的自動化測試比較
圖1 顯示了在TDD 技術下測試人員的測試過程,TDD 的測試要求的是單元測試,一般開發人員用什麼語言,單元測試就用什麼,基本上沒有選擇,在此其中,測試人員參與的機會不多,通常有了測試任務後,測試人員會將它分成測試計劃,然後再細分成測試點列表,每一份測試列表可能又對應著一份自動化測試用例,所以這個階段就需要保持三份文檔: 需求文檔+ 測試點文檔(計劃和測試點)+ 自動化測試用例,整個TDD 的過程中,自動化測試用例的編寫是在測試點列表出來之後。

圖1. TDD 技術下的測試過程



圖1. TDD 技術下的測試過程

與TDD 側重於針對單元測試不同,BDD 以用戶的目標以及他們為了實現這些目標而採取的步驟為側重點,BDD 將三種文檔進行了整合,用戶行為描述了用戶與系統交互的場景,而係統行為描述系統提供的功能場景,模塊行為描述模塊間交互的場景,整個過程中只需要一份文檔,用戶行為也是用戶需求,也是測試點文檔和自動化測試用例,隨著系統行為或模塊的行為的實現,一系列的測試活動都已經自動化了。


測試驅動開發(Test-Driven Development)

定義

TDD是測試驅動開發(Test-Driven Development)的英文簡稱,是敏捷開發中的一項核心實踐和技術,也是一種設計方法論。 TDD的原理是在開發功能代碼之前,先編寫單元測試用例代碼,測試代碼確定需要編寫什麼產品代碼。 TDD雖是敏捷方法的核心實踐,但不只適用於XP(Extreme Programming),同樣可以適用於其他開發方法和過程。

為什麼選擇

TDD執行更高質量的編程。通過TDD,可以編寫足夠的代碼來滿足測試。這會產生更模塊化,更精簡的代碼,不僅經過測試,而且更具可擴展性和可維護性。 TDD還可以降低總體擁有成本(TCO)。你有更少的缺陷。當修復成本較低時,您還可以在周期的早期捕獲缺陷。

它如何令人失望

TDD的困難之處
下面是幾個我認為TDD不容易掌控的地方,甚至就有些不可能(如果有某某TDD的Fans或是ThoughtWorks的諮詢師和你鼓吹TDD,你可以問問他們下面這些問題)

測試範圍的確定。
TDD開發流程,一般是先寫Test Case。
Test Case有很多種,有Functional的,有Unit的,有Integration的……,最難的是Test Case要寫成什麼樣的程度呢。
如果寫的太過High Level,那麼,當你的Test Case 失敗的時候,你不知道哪裡出問題了,你得要花很多精力去debug代碼。而我們希望的是其能夠告訴我是哪個模塊出的問題。只有High Level的Test Case,豈不就是Waterfall中的Test環節?

如果寫的太過Low Level,那麼,帶來的問題是,你需要花兩倍的時間來維護你的代碼,一份給test case,一份給實現的功能代碼。
另外,如果寫得太Low Level,根據Agile的迭代開發來說,你的需求是易變的,很多時候,我們的需求都是開發人員自己做的Assumption。所以,你把Test Case 寫得越細,將來,一旦需求或Assumption發生變化,你的維護成本也是成級數增加的。

當然,如果我把一個功能或模塊實現好了,我當然知道Test的Scope在哪裡,我也知道我的Test Case需要寫成什麼樣的程度。但是,TDD的悖論就在於,你在實現之前先把Test Case就寫出來,所以,你怎麼能保證你一開始的Test Case是適合於你後面的代碼的?不要忘了,程序員也是在開發的過程中逐漸了解需求和系統的。如果邊實現邊調整Test Case,為什麼不在實現完後再寫Test Case呢?如果是這樣的話,那就不是TDD了。

關注測試而不是設計。這可能是TDD的一個弊端,就像《十條不錯的編程觀點》中所說的一樣——“Unit Test won't help you write the good code”,在實際的操作過程中,我看到很多程序員為了趕工或是應付工作,導致其寫的代碼是為了滿足測試的,而忽略了代碼質量和實際需求。有時候,當我們重構代碼或是fix bug的時候,甚至導致程序員認為只要所有的Test Case都通過了,代碼就是正確的。當然,TDD的粉絲們一定會有下面的辯解:
可以通過結對編程來保證代碼質量。
代碼一開始就是需要滿足功能正確,後面才是重構和調優,而TDD正好讓你的重構和優化不會以犧牲功能為代價。

說的沒錯,但僅在理論上。操作起來可能會並不會得到期望的結果。 1)“共同開發”其並不能保證開發的兩個人都不會以滿足測試為目的,因為重構或是優化的過程中,一旦程序員看到N多的test cases 都failed了,人是會緊張的,你會不自然地去fix你的代碼以讓所有的test case都通過。 2)另外,我不知道大家怎麼編程,我一般的做法是從大局思考一下各種可行的實現方案,對於一些難點需要實際地去編程試試,最後權衡比較,挑選一個最好的方案去實現。而往往著急著去實現某一功能,通常在會導致的是返工,而後面的重構基本上因為前期考慮不足和成為了重寫。所以,在實際操作過程中,你會發現,很多時候的重構通常意味著重寫,因為那些”非功能性”的需求,你不得不re-design。而re-design往往意味著,你要重寫很多Low-Level的Test Cases,搞得你只敢寫High Level的Test Case。

沒有留言:

張貼留言

網誌存檔