使用測試用例來約束本身的代碼

寫測試代碼這種事情 ,之前只在網上和書上看到過, 本身歷來沒有寫過。 每當看到那些世界頂級程序員編寫的技術書籍中出現「測試用例」「測試代碼」的字樣或者一些行業的鼎鼎大名的技術大牛們說起寫測試的重要性的時候,個人內心就會產生一種本身編的必定是假程的錯覺, 爲何我寫代碼就歷來不用那玩意?程序員

 

就拿開發一個MVC框架的Web應用程序設來講, 一般的作法就是新建一個控制器和一個模型, 把代碼要實現功能的業務邏輯寫在模型裏面,控制器調用模型, 假若有外部參數則接收參數傳遞給模型, 假如業務邏輯過於複雜致使模型過於臃腫或邏輯不暢, 則再進行梳理或提取,構建成一個新類,再由模型進行調用。 這一過程反覆循環迭代, 直到功能開發完畢。 調試或者測試寫的代碼是否能得出想要的結果, 天然也是使用最簡單粗暴的方法, 在瀏覽器中運行程序, 定位到控制器, 控制器調用模型, 模型再調用其它所涉及到的類,拿到結果後再一步步返回, 瀏覽器是否顯示預期結果就意味着咱們寫的程序是否正確。無論是咱們要測試的功能模塊離控制器只有一個調用仍是有十個調用,都遵循着這樣一個步驟, 由於這是最符合咱們直覺和習慣的方式。 我也一直以這種方式在開發程序。編程

 

本來這也沒有什麼問題,咱們所寫的代碼邏輯是經過咱們的大腦深思熟慮組織後產生的,一般狀況下咱們有這個把握能夠肯定代碼邏輯運行的正確性,就算出現意料以外的狀況, 多點幾下瀏覽器的刷新按扭也能把問題找出來解決,由於咱們對代碼的運行邏輯瞭然於胸,自信不會出什麼叉子,一旦出現了叉子那就產生了所謂的程序BUG。瀏覽器

 

然而, 萬事總有例外, 致使咱們以往的經驗失效。 就拿我最近碰到的一件事情來講,公司有一個項目因性能優化須要,對部分功能進行技術方案調整, 重寫了代碼。代碼量不大, 功能自己的代碼和其依賴的通用函數代碼加起來一共也就二三百行,可是隱含在背後的邏輯卻異常複雜,涉及到的數據表也有五張。我將這部分須要重寫的代碼重頭至尾仔仔細細讀了一遍, 勉強能理解每個語句塊都幹了些什麼。 多是我邏輯思惟能力不過關, 也有多是代碼太過於複雜 , 我沒有辦法將全部這些代碼的前因後果全盤瞭然於胸,也就沒有辦法從全局的角度去梳理代碼邏輯肯定優化方案,我只能從局部的角度出發, 依樣畫葫蘆的按照舊方案從新實現一遍代碼的邏輯, 在實現的過程當中如發現有優化的餘地則進行局部優化,等到足夠熟悉全局邏輯後,再從宏觀的角度對代碼結構進行調整優化,這麼作效率是低了點,倒是最保險的作法。安全

 

我照着舊代碼寫出一個個如出一轍的函數,卻沒有辦法肯定這些函數的運行結果是否能得出預期的結果,鬼知道換一種語言實現之後, 函數吐出來的結果仍是不是和以前的同樣,我可沒有jeff dean那樣牛逼,預判代碼的結果比編譯器還精準。原本這也不是什麼大問題,把代碼跑一遍,當執行到這些函數的調用時天然就知道結果了。問題出在這之中某些函數和代碼的入口隔着七八個調用,並且其中某些調用由於依賴於某些if條件判斷結果而不是必然被調用到的,要構造出能使這些函數被調用到的if條件判斷分支走向的參數環境是一件異常繁瑣的事情,光想一想就讓人以爲煩躁和睦餒。另外一種方法就是把函數的調用代碼複製一份放到執行入口的開始位置,這樣代碼一運行就直接能調用的到了。 然而, 這種方法也會帶來問題,如性能優化

 

函數處於不一樣的類和包內,調用函數須要導入包和實例化類,而作這些事情對項目的自己沒有實際的意義框架

 

某幾個函數只在所在的類內被調用, 訪問修飾是private, 經過這種方法測試它的準確性還須要放開權限把訪問修飾聲明爲public, 調試完畢後還得改回去, 操蛋函數

 

有多個分佈在不一樣類之中的不一樣函數須要以相似的方式測試, 反覆進行這些無心義且繁瑣的操做, 極度浪費時間,影響心情性能

 

代碼的執行入口總放着那麼一坨被註釋掉的代碼,想拿掉又怕拿掉之後下次還要用, 心裏掙扎的難受單元測試

 

所以, 想要解決這個問題, 上面的兩種方案都不可取, 柔腸百轉也想不出像樣的解決方案。 長輩們都說編程都是腦力勞力, 我以前不覺得然, 但當碰到這些想破腦殼也找不到辦法的問題時就不得不認可, 編程的確是腦力勞力。我才20歲,外表卻有30歲能夠看,我想也跟長期被這些問題困擾有必定的關係(我說的是10年前的本身)測試

 

我思前想後,檢索全部腦子中關於程序設計的資源, 才找出一個以前歷來沒有嘗試過的方案, 引入單元測試。我這我的有一個優勢, 在工做上碰到陌生的東西曆來不會望而卻步,只要有用處, 都會去積極嘗試。對於單元測試,我雖然沒有掌握使用的方法, 可是網上查查資料, 看看教程, 我相信花不了多少功夫就能搞出來。 事實也的確如此, 只看了一篇資料,照着教程的步驟操做就把測試程序跑起來了。 我使用的是go語言, 按照go test的規則 ,被測試的代碼所在的文件名加上test後綴便可做爲測試代碼所在的文件的命名,以下圖

測試函數的命名方式必需要以Test做爲前綴, 以下圖

測試代碼編寫完成後, 在代碼所在的文件目錄下使用cmd運行go test命令,測試代碼就可被運行了

須要測試的函數在測試代碼中被直接調用, 省去了跟蹤龐雜代碼執行走向的麻煩,從複雜的業務邏輯中解放出來, 很是的清晰方便。

 

從表面上看, 寫測試代碼的好處就是方便測試函數的正確性, 然而, 隨着以後代碼的編寫, 我發現寫測試代碼所帶來的好處不止於此。當有了要爲代碼編寫測試用例的前提條件後, 我在實現某個函數時就約束本身, 這個函數必需要方便編寫相應的測試代碼。有了這層約束之後, 我發現寫出來的代碼的質量要比不寫測試用例時高, 好比

 

函數的功能職責更加單一了,換言之, 函數的邏輯更穩定了, 不易產生變更, 由於我不想我辛苦編寫的測試代碼隨着函數的代碼的調整而付之一炬。

 

不會很隨意的把代碼亂放, 寫出來的代碼更加整潔,該提取函數時就建新函數, 該內聯函數時則刪除沒必要要的函數,在以前, 爲了偷懶每每會對這些細節視而不見, 這會加速代碼的腐爛。

 

更早的發現BUG,不少時候, 程序的BUG都是在生產環境中由用戶發現,緣由很簡單, 開發項目的速度和質量這對冤家之間程序員每每會選擇前者,此外, 程序員會毫無根據的信任本身寫的代碼,所以當向程序員反饋BUG時,他們都會保持懷疑的態度。不少時候, 程序員寫一個函數一般只給一個特定的輸入,運行後發現輸出如本身預期那樣後就默認這個函數是健康的, 事實上, 當給這個函數另外的輸入時, 函數吐出的結果就在預期範圍以外, 這便致使了BUG的產生, 箇中緣由即是對本身直覺盲目的信任, 認爲本身的大腦就是一我的肉編譯器。 編寫測試能夠很大程度上的杜絕這類問題

 

一般,咱們會認爲編寫測試是一件浪費時間的事情, 而後就是一邊向別人吹牛一邊則啪啪啪的打本身臉。 除此之此, 在開發項目時經常以邏輯不穩定隨時須要調整代碼爲理由拒絕寫測試,然而, 當從相反的方向來考慮問題時會發現, 有了測試的約束後,咱們會更加仔細和嚴謹去編寫每個函數 ,逼迫本身更加深刻的考慮問題而防止代碼走樣, 提升代碼質量、安全性以及穩定性, 這也是寫測試所帶來的相當重要的意義。

相關文章
相關標籤/搜索