年紀大了,腿腳不利索,拄着柺杖走路,走的穩不說,還能預防跌倒。程序員
但若是真的跌倒了呢?安全
跌倒後有沒有人敢扶?扶起來還能不能走?若是能走,走得還能不能像之前那樣快?若是不能走,是否是要去醫院?數據結構
沒了柺杖,產生了災難性的骨牌效應。單元測試
單元測試之於開發人員,至關於老人的柺杖,離開柺杖,也能走,但就是深一腳淺一腳,並且還有隨時跌倒的危險,跌倒以後還會產生一系列的問題,搞的人焦頭爛額。測試
在沒有單元測試支撐的狀況下寫代碼,你不會知道代碼裏面有沒有邏輯BUG,是否符合預期,不能發現編碼過程當中引入的錯誤,更不能發現設計和需求中存在的問題。編碼
我曾經所在的一家公司,開發人員是不寫測試的,他測試本身代碼的方法,是寫完以後運行一下,點點看有沒有問題,效率低下容易漏測不說,還很業餘,簡直侮辱軟件工程師這個高大上的職業(看我鄙視的眼神)。spa
假設你寫了一個服務,每寫一個方法你都寫單元測試將方法中的路徑全覆蓋掉,如異常,if-else, switch語句等,剛準備提交,忽然接到通知,需求變了,你不得不改動編碼邏輯,這個時候怎麼辦呢?首先要跑一遍單元測試,確保你當前功能的測試全跑通,而後分析需求,按照要求對相應的代碼進行了修改,以後,修改或增長單元測試對改動代碼進行覆蓋,你點下了開始按鈕,看着全部測試都打了綠色的對勾(✔),你從容淡定的提交了代碼,拿起菜刀,哦不,端起水杯,跟分析師說:改好了!你看下是否是醬嬸兒的?設計
咱們一塊兒來看看剛纔發生了什麼。調試
首先,由於編寫了全路徑覆蓋的測試單元,因此你不怕需求變動,也就是說,單元測試對於重構或者需求變動來講,能讓咱們對編寫的代碼更有信心。接口
其次,能夠預期遇到的錯誤,是冒泡交給上層邏輯仍是在方法體內消化掉,都在你的掌握之中。即使咱們編碼或者寫測試的過程當中沒有發現這些異常,有想不周全的地方,後面遇到了這個異常,也能夠修改測試將其覆蓋到測試裏面。咱們對本身寫的程序有了全面的瞭然於胸的掌控。
比較完備的研發團隊,通常都會配置測試部門,在接到需求文檔以後編寫測試計劃,開發人員結合需求文檔,閱讀測試計劃,能夠很快理解項目的流程和操做場景。甚至有經驗的開發能夠直接依據測試計劃使用TDD模式快速實現。
但大多數開發仍是使用的編寫邏輯邊單測的模式,因此這裏說一下在業務支撐型項目的開發中,咱們寫單元測試的原則,並簡單介紹一下經常使用方法。
首先要說到的,是項目和數據依賴問題,這個問題分析起來,首先要問你這個測試方法的測試目標是什麼?是測試代碼的業務邏輯仍是測試項目依賴的元數據。若是是前者,咱們徹底能夠編寫面向業務邏輯的測試單元,數據部分則用Mock解決。但若是是後者,你須要確保在測試、生產等環境裏項目依賴的元數據存在才能正常運行,那麼,能夠專門編寫測試單元來檢查當前環境下是否存在該元數據的定義及存在預期的數據定義。這個例子中,一個是檢查代碼邏輯,一個是確保項目正常運行,是兩個不一樣目標的測試單元,因此,一個要用到Mock,一個須要檢查環境。
而後咱們說外部接口和項目依賴。這個問題比較常見。對於所依賴的外部接口,咱們必須假定它是不穩定的,編碼時要作好降級準備(如接口無響應,返回值錯誤等狀況的處理),給用戶一個友好的反饋。那麼怎麼測試呢?
一樣,須要分別寫兩個測試單元,一個用來檢查調用外部接口的方法的返回值,是否符合外部接口的期待;另外一個測試單元用Mock模擬外部接口返回的各類結果來檢查咱們的後續邏輯。
爲何不直接調用外部接口測試呢?那是別人家程序員的任務啦!
標準的團隊都會配置一個測試小組,開發任務完成後,提交測試。測試組的同事使用各類姿式虐待咱們的項目,將找到的BUG提交給咱們進行修復。這個時候,咱們第一件要作的事情仍是編寫單元測試,去復現這個BUG,而後再去修改代碼,直到BUG再也不出現。這也是對測試同事的尊重,保證你再次提交代碼後,這個BUG不會重複出現。
這句話聽起來有點反人類。但事實上,編寫單元測試不但不會形成項目延期,反而會使咱們的工做目標更明確,從而使編碼工做更高效,最終每每會提早完成目標。
爲何會這樣呢?由於目標很明確,你會少寫不少臆想的代碼邏輯,再加上這些猜想着寫出來的代碼還可能存在BUG,後果就是你花了很長時間在調試修改一段沒必要要的邏輯。
隨着迭代的邏輯愈來愈複雜,由於有着測試的支撐,每次修改和功能的增長,變得輕量而敏捷,優雅而神祕。
可能有同事以爲「重構」這個詞太過恐怖,認爲只要是重構,就是對程序結構、數據結構的推翻重來。但那些注重成長的程序員非但不會認爲重構恐怖,還會將重構做爲成長路上的最好的夥伴。
重構的頻率,最好是每次提交代碼前,對本身的代碼進行一次自審。問本身這段代碼是否過於繁瑣?有沒有更簡潔的方法?它的可讀性好很差?可維護性怎麼樣?若是代碼量比較大,或者你正在審查本身多個里程碑的代碼,可能還會問本身關於設計原則和模式方面的問題。
重構的間隔太長,會演變成嚴重的技術債務,而這些技術債務的償還,纔是本節開頭所說的,對程序結構、數據結構都會有很大的改動,相較於每日自審重構,複雜度、數據風險以及開發成本都會成爲使人頭疼的問題。尤爲是當你去重構「前任」留下的代碼時,那心情,非常酸爽。因此,爲了避免讓咱們的「後來者」酸爽,請堅持每次提交前的自我審查和重構,固然,前提是你寫了單元測試。
一個事實是,用戶的需求隨着業務須要一直在變化,因此咱們的程序也一直在迭代,要想保證咱們每次的迭代又快又穩定(或者調整現有功能,或者增長新的功能),咱們必須給本身一個安全措施,這就是單元測試。
因此,不要怕重構,每次提交前審查代碼->重構代碼->執行單元測試,應該成爲咱們每次提交前固定的工做流程。
單元測試和重構,成長路上的好夥伴。
研發中心 張鵬
2019-11-29