談談測試和程式碼質量
畢業找工作那會,有個開發的同學被分配去做測試,當時很不理解。為什麼他平時都是用 Java,怎麼去做測試呢?當時對測試的認知就是點點點。
在工作一段時間後,對於測試依然有一定程度的偏見。為什麼有偏見,還不是因為無知!人類對於不瞭解的東西,很容易形成偏見 。
當時覺得開發的功能,進行一下簡單的測試就可以了,功能正常就 OK 了。也一直是這麼做的,也沒有出什麼大問題。畢竟框架都是現成的,寫寫業務程式碼沒啥難度。
後來自己開始開發新的通用模組,上層很多業務都需要用到的功能模組。第一版功能實現後,後續就不怎麼敢修改了。即使修改,也是戰戰兢兢的,擔心引發大規模的問題。如果只是自己用,出問題了還可以控制,關鍵是我們開發的是 API,只要出問題,依賴我們的各個程式都會有問題,這個影響就不可控了。並且問題總是會延遲很久才會出現,出現後定位修復提交得時間,重新出版本也需要時間,對方替換驗證也需要時間,整個週期太長,影響面很廣。
所以,每次提交底層程式碼前,都會進行“充分”的測試。當然,這個充分是自己以為的以及環境允許的充分,因為很多環境都不在了,不能保證改動的每個地方都能被測試到。所以,每次提交底層程式碼,依然會緊張,因為我不能 100% 的確定程式碼質量。
只要提交程式碼,就有犯錯的可能。如果對於錯誤的處理沒有一系列完善的措施,就會導致人人都“不求有功,但求無過”的心理。雖然程式碼寫的很噁心,但是基本功能都是被驗證的,所以不會想著去優化;雖然程式碼中有雷,容易導致別人改程式碼加功能時踩坑,你也不敢去改,畢竟沒有完善的環境給你測試。所以,程式碼從提交後,就基本不會變了,雖然各種不友好。
踩了坑,你對問題的認知才會更深刻。才會更加知道測試的重要性。如果只是停留在知道上,那麼依然是止步不前。重要的是,測試到底多重要,怎麼保證測試的質量,怎麼用測試充分保證程式碼質量。
為了對測試有更深刻的認識,前後陸陸續續看了測試相關的書,譬如《谷歌測試之道》,《微軟測試之道》,《持續交付》,《測試驅動開發》,《自動化測試》等等。研究及使用了 Google Test, CppUnit等 C++ 測試框架,對於 Python,Golang 的測試也有了初步的瞭解。對單元測試,冒煙測試,整合測試,灰盒測試,白盒測試,黑盒測試都有了一定程度的認知。瞭解的越多,對測試的重要性也越認可。
測試可以分為自動化測試及人工測試。自動化測試依賴寫好的大量的測試程式碼而保證質量,而人工測試通過手動操作來保證質量。手動測試依賴UI測試用例,很多情況下屬於黑盒測試,很多功能並不一定能夠覆蓋到。但是人工測試不可少,因為有些功能必須有人的介入才能夠確定是否正確。自動化測試和人工測試結合起來,能更好的保證質量。
當然,自動化測試和手工測試都需要充分的測試用例。這需要對功能,對程式碼,對業務的深刻理解。如果對業務沒什麼理解,就各種設計測試用例,測試用例的質量就會大打折扣。如果只是為了走個形式,為了寫測試用例而累測試用例,也沒這個必要,個人沒成長,對業務也沒啥幫助。
自動化測試用例需要反饋,譬如程式碼覆蓋率,執行結果的自動反饋等等。和持續整合或者持續交付結合起來,才能發揮其最大威力。
有一種很好的保證程式碼質量的方法:測試驅動開發(TDD),其理念真的是非常好,實際作用也很大。當把它引入程式碼開發時,對於功能的完整性,對於程式碼的可讀性,程式碼的質量等都有很好的保證。有了前期開發的測試用例,後續改動引起的問題,測試用例一跑就能發現,程式碼質量得到了很好的保證。
之前有利用 Jenkins 搭建了持續整合的平臺,從程式碼提交,到測試,都是自動化的流程。測試用例跑不過時,覆蓋率不達標時,Coverity 新增問題時,都會通知相應的程式碼提交人。那時真正的意識到持續整合的好處。
在學習及實踐了自動化測試,搭建持續整合平臺後,依然有個問題繞不過:你怎麼保證你的測試環境是充分的,是完善的?因為測試用例要基於具體的環境才能明確其效果。如果環境不穩定,你怎麼保證測試用例的執行情況?
這個問題困擾了我很長時間。為了測試充分,你得有充分的測試環境。如果你的環境依賴於第三方,譬如裝置,你怎麼保證?你不可能搭建各種裝置環境,單獨給你測試用,這樣成本太高了。為了解決這種問題,你可以通過 Mock 實現,可以開發模擬器,模擬和裝置的互動,保證測試環境的穩定。
18 年底,我開發了協議模擬器,對程式碼改動後,先用協議模擬器進行驗證。不用費時費力的去借裝置,開發效率得到了很大的提高。有了模擬器,我敢對程式碼進行修改和完善,因為我有環境,可以通過具體而詳細的測試用例保證質量,真正的藏到了環境完備和自動化測試的甜頭。
測試往往是一個整體的過程,需要整體的設計與規劃,不應該想到什麼就做什麼。當測試用例及測試環境完善後,通過測試用例倒逼程式碼的完善和重構。在沒有充分的測試用例的情況下,談程式碼的重構都是扯淡。這種做法的後果就是埋下無數的雷,後人排雷不知道要用掉多少人力和物力。排雷多了後,人的鬥志和信心都被打磨的乾乾淨淨,也不會有完善優化程式碼的想法。
如果有一個完善的持續整合(持續交付)流程:程式碼提交後觸發編譯,程式碼掃描,單元測試,進而冒煙測試,再是整合測試,最後部署到生產環境中。整個過程形成一個閉環,及時反饋,使得引入的錯誤及缺陷及時被發現,減小代價。
現在也逐漸明白了大廠的開發測試工程師那麼吃香的原因了,保證程式碼質量真的很重要。任正非任老爺子說:我們要從最基礎的編碼質量做起,視高質量程式碼為尊嚴和個人聲譽。真的很認同這個觀點,保證自己程式碼的質量本是是基本的事,但很多時候我們卻保證不了。所以他才把程式碼質量提到那麼高的高度,而程式碼質量離不開測試。程式碼質量保證了,功能才能穩定,穩定可靠的功能就是最好的宣傳。保證程式碼質量就是程式設計師練內功,內功紮實,才能在上面構建更多的可能性。