今天看了不少朋友轉貼了一些關於 TDD 跟 Unit Test 寫得還不錯的文章,讓我想要順便分享一下一些想法。
很多團隊覺得自己需要 TDD 來提昇產品品質,來提昇 code coverage,來避免改 A 壞 B 的情況,但他們絕大部分都還分不清楚「Unit Test」跟「TDD」的差異。
對他們來說,TDD 就是 Unit Test first,先寫測試,再寫產品代碼。
然而 TDD 遠比 Test First 具備更多的效益,以及相關的技能。
拉回來我想說的,如果一個團隊要搞 TDD,通常我都會先看他們是不是已經把 Unit Test 搞到一定的程度了。
Unit Test 實踐到一定程度時,碰到的瓶頸就會需要透過 TDD 來解決,既享受測試的保護、產品操作說明文件的好處,又沒有「針對 legacy code 後補測試的成本問題」,又不會只是「為了測試產品代碼的正確性,而寫單元測試」。
跳過 Unit Test 想要直接搞 TDD,這步子邁大了,容易扯著蛋。
想要搞 Unit Test 也是一樣的,團隊有沒有 build server(CI server),如果沒有,那 Unit Test 也只是自己寫爽的而已,因為其他人根本不會拉下來跑。
想要搞 build server 也是有前置作業的,團隊有沒有對應的 version control system,如果版控的機制與策略不落實,那 CI server 的運作就不 work。
例如有些專案還沒上到 CI 上,有些在 CI 上的專案有寫測試但根本沒 hook run test 的 event。
或是 CI 上測試 failed 了,build failed 了沒人要修。
或是測試時好時壞的,團隊覺得這是一件習以為常的事。
這些都需要比 TDD 更早點發生,這些問題還沒解決,TDD 真的還太遠。
最後一句話,「TDD 不該被定義成團隊的開發規範,而該是 developer 的良好開發習慣。」
TDD 只是個投資報酬比相當高的開發方式,能用些許成本來達成多個目的的手段。
如果大家的 TDD 是一種可能製造浪費的方式,而不是反過來,更快、更小的驗證可行性,產出結果取得回饋做調整,那你的 TDD 很可能用錯地方,或是壓根就誤解 TDD 了。
unit test 目的 在 91 敏捷開發之路 Facebook 的最佳貼文
今天看了不少朋友轉貼了一些關於 TDD 跟 Unit Test 寫得還不錯的文章,讓我想要順便分享一下一些想法。
很多團隊覺得自己需要 TDD 來提昇產品品質,來提昇 code coverage,來避免改 A 壞 B 的情況,但他們絕大部分都還分不清楚「Unit Test」跟「TDD」的差異。
對他們來說,TDD 就是 Unit Test first,先寫測試,再寫產品代碼。
然而 TDD 遠比 Test First 具備更多的效益,以及相關的技能。
拉回來我想說的,如果一個團隊要搞 TDD,通常我都會先看他們是不是已經把 Unit Test 搞到一定的程度了。
Unit Test 實踐到一定程度時,碰到的瓶頸就會需要透過 TDD 來解決,既享受測試的保護、產品操作說明文件的好處,又沒有「針對 legacy code 後補測試的成本問題」,又不會只是「為了測試產品代碼的正確性,而寫單元測試」。
跳過 Unit Test 想要直接搞 TDD,這步子邁大了,容易扯著蛋。
想要搞 Unit Test 也是一樣的,團隊有沒有 build server(CI server),如果沒有,那 Unit Test 也只是自己寫爽的而已,因為其他人根本不會拉下來跑。
想要搞 build server 也是有前置作業的,團隊有沒有對應的 version control system,如果版控的機制與策略不落實,那 CI server 的運作就不 work。
例如有些專案還沒上到 CI 上,有些在 CI 上的專案有寫測試但根本沒 hook run test 的 event。
或是 CI 上測試 failed 了,build failed 了沒人要修。
或是測試時好時壞的,團隊覺得這是一件習以為常的事。
這些都需要比 TDD 更早點發生,這些問題還沒解決,TDD 真的還太遠。
最後一句話,「TDD 不該被定義成團隊的開發規範,而該是 developer 的良好開發習慣。」
TDD 只是個投資報酬比相當高的開發方式,能用些許成本來達成多個目的的手段。
如果大家的 TDD 是一種可能製造浪費的方式,而不是反過來,更快、更小的驗證可行性,產出結果取得回饋做調整,那你的 TDD 很可能用錯地方,或是壓根就誤解 TDD 了。
unit test 目的 在 91 敏捷開發之路 Facebook 的最佳貼文
解決問題的起點是,「發現問題」跟「面對問題」
學習起點只是知識點,學習的內化則是將知識點與自己既有的知識體系建立成知識面。
會用就好只能應急,只能把別人的詩朗誦地很好聽,但始終無法成為大詩人。
前端的世界更是如此,因為框架推陳出新的迭代速度更快,只有了解了本質,在熟悉新框架才能只需要關注在「差異」、「適用場景」、「優缺點」。
不了解本質,就只能像狗追尾巴一樣,一直被學習新框架搞得團團轉。
沉澱了兩天,其實上完課後還在整理家裡,到今晚才能夠好好再回顧一下上週六日所學到的內容。
這次的「Clean Coder: DI/AOP 進階實戰」課程,在過去的工作經驗中已經有使用 DI 在產品代碼上的經驗,上課前就一直在猜想著 91 究竟會用什麼樣的方式來帶我們進入 DI/AOP 的實作。課程一開始讓我們重新體驗寫個 #乾淨的胖子 開始。接著帶著我們思考這樣樣的程式究竟有什麼樣的問題,並透過重構的手法將胖子瘦身。平時在開發產品時通常寫到這裡就會結束了,看起來很乾淨、又不肥。但事實上卻只是將一坨垃圾分成數個小堆掃到桌子底下,看起來很乾淨,但其實垃圾仍然存在。
#不知道有問題
> 最怕的就是你覺得沒有問題,但實際上問題很多。
這門課最精華的莫過於是 91 帶著大家重新思考每當需求變更時如何以改最少的 Code 來達到目的,如何不動現有的 Source Code,而寫新的物件來取代或組合上去,這考驗著如何在程式碼中實踐 SOLID、OO 等設計方法。
> 什麼是實作?什麼是Flow?什麼是設計?
平時寫 Code 時很容易將需求都直觀的依順序寫下來,所造成的現象是當需求變更時我的 Production code 要修改、呼叫端要修改、Unit Test 要修改,這也是我一直困擾的問題。每當這樣的狀況時我總要額外花上許多心力在修改 Unit Test。91 帶我們重新思考需求與 Code 其實是可以拆開來看的,別一股腦的把需求攤開轉成 Code 實作。要能透過各種設計方式,將物件組合在一起來達到需求。
#動手解決問題
這兩天的課程就是在不斷的思考可能的問題→找出問題→思考如何解決→動手寫Code 的迴圈,每當解決一個問題時心裡總會想到在工作時的某段 Code 也是同樣的問題,我也許可以拿來先試著修改看看,心裡充滿著想趕快動手的衝動。這門課不是在教你怎麼用 DI/AOP,而是該怎麼用這些 Framework 來解決問題?
Resharper 也多學了新招,每次回來上課總能再多學到關於 IDE 操作的技巧,而不是只能看著 vim 的游標在那邊閃啊閃,卻還是拿著滑鼠裝忙…😅
unit test 目的 在 [討論] 多少公司有執行單元測試分享- 看板Soft_Job 的美食出口停車場
關於自動化測試可以參考我多年前的拙作
https://www.ptt.cc/bbs/Soft_Job/M.1338221262.A.0AC.html
不過現在我們在討論單元測試,所以我將把我的文章內容縮小到「單元測試」
上面。
我待過四間公司,寫過C#, PHP, Python, Java,而這四家公司不管小接案公司
,網路公司,跨國軟體公司或是大型傳統產業,通通都沒有養成所有人普遍撰寫
單元測試的習慣,倒是我聽說一些朋友在比較偏小型的start up或是小型軟體
公司,比較有在做Unit Test。
很多人在談Unit Test的時候會把Unit Test跟Integration Test混在一起,然後
說Unit Test要付出很多effort,實際上,他是把Unit Test跟Integration Test
混在一起講了。
雖然這些這些公司都因為種種原因沒有做Unit Test的習慣,但是我在這四間公司
裡面全部都有自己做Unit Test,而即使有做Unit Test,我的品質與速度都比其
他人要快。
很多人在做Unit Test有一個盲點,就是為了做單元測試而做單元測試,因為上面
一個方案下來,說我們的專案要有幾個test case,要達到多少coverage rate,
這樣才叫做品質好,卻經常沒有從Unit Test的ROI出發。
另外一項造成Unit Test會花上許多時間的原因,就是物件的依賴程度太高,又
不懂得使用Mocking技術或是沒有讓程式有足夠的測試力,導致做單元測試會影響
到整體開發時程,這樣單元測試就變成累贅了。
「你終究要測試你的程式的,為什麼不做單元測試呢?」
如果你的單元測試是為了減少你的測試時間用的,減少測試時間進而減少整體
開發時間,那你為什麼不做呢?
給一些還沒有做單元測試的朋友一些體會到單元測試的切入點:
1. bug的單元測試
如果發現bug,嘗試用單元測試的方式找到那段有問題的程式碼,然後撰寫一個
單元測試程式,以後迴歸測試時要執行這個測試。
2. 減少耗時的I/O
network, storage這些東西都會造成你後續測試的時候消耗很多時間,透過mocking
技術, 機制將這些I/O的部分都去除掉,每次測試執行時間可能從幾分鐘縮短到幾秒
,這會是天差地別的差距。
3. 選擇依賴關係高的程式來做
很多人在寫單元測試的時候會挑外圍的程式來說,這些外圍程式大多沒有太多的依賴
關係,所以出問題的機會也少,程式也相對容易理解,反觀那些高依賴關係的程式,
由於跟其他類別之間大量耦合,要測試裡面的內容相對來說困難許多,透過mocking
來切割待測類別與其他類別之間的依賴關係,這樣就不用花這麼多時間準備整合測試
資料。
反觀依賴度低的類別,測試資料準備與驗證相對簡單,雖然做單元測試也快,但ROI
卻很低,做久了,會很沒有成就感。
4. 思考單元測試減少的載入時間
除非你有用JRebel或是類似的東西,否則你在開發Spring Java程式的時候不免必須
不斷restart你的application或是你的container去bootstrap Spring managed beans
,這些在測試階段會花上非常多的時間。
當然Spring有提供JUnitRunner或AbstractTestNGSpringContextTests來供你產生單元
測試用的spring context,但當你類別多的時候還是很花時間的,這時候如果透過具備
Mocking功能的單元測試來完成你程式碼的測試作業,將可以大幅縮短之後的測試時間。
以上這幾點達到的測試覆蓋率可能不太高,但你應該會找到程式要測試的重點,至於
單元測試是要程式開發前(TDD)或是開發之後做,這要看你使用什麼樣的mocking技術。
重點是不要為了去做Test而去Unit Test,重點是分析這樣做以後能達到多少ROI。
最後再來談談「單元」,每個人對於單元的定義可能都有所不同,但基本上的認知是,
單元測試是在測試「程式碼」最小界定範圍為「一個function」或是一個類別,所以
單元測試的目的在於測試function或class是否有達到預期。
當然function或class之間是有dependency存在的,單元測試的目的是去除這些
dependency讓整個測試可重複執行並且不會因為其他單元的問題或不存在而造成
待側單元的錯誤。事實上我認為單元測試最大的關鍵是怎麼透過各種方法去消滅
這些dependency的能力,實際上你學的不是測試方法,而是mocking方法。
如果你是用Java的話推薦使用無敵mocking framework JMockit,完全不用對你
現有的程式進行改造,一樣可以mocking。
其他透過撰寫測試的過程當中知道怎麼樣去規劃元件之類的好處我就不說了,
台灣這邊的軟體產業之所以會有種種問題,一部分就因為對於unit test帶來
的好處與方法沒有正確的認知所導致。
--
~四十八個德瑞克~https://blog.derekhsu.homeip.net
馬皇本紀:https://blog.derekhsu.homeip.net/2009/08/821
藍澤光的身世之謎:https://blog.derekhsu.homeip.net/2010/09/1610
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 175.181.111.225
※ 文章網址: https://www.ptt.cc/bbs/Soft_Job/M.1478187696.A.46A.html
那就叫做integration test,不是unit test。
至於要不要重構這件事,如我所說,這跟你用的是什麼mocking tool有關,如果是
JMockit,那別擔心,你的程式就算是垃圾都不用重構也可以去除所有dependeny來做
unit test。
如果沒有這種framework可以用(C# https://www.typemock.com/isolator-product-page
這個可以試試看,但這是commerical的),unit test帶來的好處是refactor之後的
更好的系統架構。
※ 編輯: derekhsu (175.181.111.225), 11/03/2016 23:54:43
... <看更多>