目前在測試開發行業已經摸爬滾打了十年,一直忙於工作,基本沒有多少時間可以靜下心來進行沉澱。現在,終於有了個機會,可以對自己的測試開發生涯十年進行一次總結,希望這次能夠寫完吧。
文章較長,大致目錄如下:
從畢業後,我幹了兩年的PHP開發,可能因為不是專業原因,也可能是因為天賦原因,遇到了一些瓶頸,在技術上始終沒到質變的過程。機緣巧合之際,遇到了一個好領導Z總,他在簡單面試過我後,就決定同意我轉入到QA部,擔任測試開發工程師,也給我晉升了一級,在第一年,領導開始給我定了CICD的方向,把專案的CICD給打通了,當時應該是2013年的時候,devops沒像現在這麼火熱,但是因為教育系統的複雜性,大家都意識到,這玩意兒,沒有CICD可不行,每天出問題,都是使用者第一個發現。
於是我們開始研究CICD的技術方案,當時用的是jenkins和teamcity,為什麼用兩套,因為開發團隊又有C#.NET幫,又有PHP幫(手動狗頭,逃!),teamcity對C#顯然支援更好,而PHP當時有xinc,hudson(如果我沒記錯的話),jenkins,當時jenkins從hudson出來後,社群活躍,所以選擇他當然沒錯,所以一款產品火不火得起來,好的社群很重要。
當時CICD的流程,是先更新程式碼,然後跑單元測試後,跑端到端測試,單元測試和工程程式碼是放在一起的,但是端到端測試,程式碼是獨立的管理方式,這就導致兩個流程沒法很好的串聯起來。
我於是用剛學的開發了一個ci_sync的同步工具指令碼,整合到了jenkins,自動拉取端到端的測試程式碼,並對一些設定指令碼進行分析,替換一些環境變數,並去除一些不必要的偵錯程式碼,其實就是類似autoconf、automake這類的構建系統,只不過不像autoconf那麼複雜,我沒有這塊基礎和背景,所以還是選擇簡單實現,採用大量正則進行匹配替換。這個實現很醜陋,所以我後面也開始學習一些類似語法解析的技術,來進行指令碼的解析和處理。指令碼開發完以後開始用起來,後面就開始一直埋頭優化和維護這套指令碼。但是,Z總找到我說,雖然我能力還行,但是距離他的期望,其實有挺大距離,他希望找到的是一個測試架構師,現在他不知道該不該把這個位置留給我。雖然我不知道這個架構師到底是個啥,但是還是默默答應下來,好的,我會成為一個測試架構師,事實上,我後來也看了《測試架構師修煉之道》,但是咱就是個社恐,理念可能略懂,但是要跟開發大佬們滔滔不絕,咱還是沒這個底氣。
上一節咱談到了測試架構師,在我看來,實在也不懂這條路怎麼走,後面應該是又一個機緣巧合,幾個測試小組開始研究起了介面測試框架,大公司就是這樣愛一起扎堆造輪子。我的大Z總知道了這個事,又出面了,搞了個workshop,叫上了部門的幾個技術大牛,當然,好像也包括我,一起去PK介面測試框架用哪個。我有點頭疼,你安排我做行,讓我去爭,我還是有點犯蹙的。不過,既然領導開頭了,咱硬著頭皮也要上吧。我的程式設計哲學其實是很不入流的,大部分人是先有雞(規劃)再有蛋(實現),而我遵循的是,這個水分子就是由H元素和O元素構成的,你拿HO還可以組成雙氧水,你可以在頭腦裡有個大概的樣子,但是你沒法清晰定義他,就嘗試著寫把他組合起來看看吧。所以,我在這個過程中,我寫了個http請求的lib,然後再把他放到unittest裡,這個就是一個測試框架的雛形,這樣對嗎,好像對,也好像不對,跑能跑,少了點啥,unittest的報告可太醜了,不直觀。所以,又找了個htmlrunner,把測試集扔進去,報告出來了,有點好看了,但是程式碼還是很醜,還有bug,所以我就把htmlrunner拆開來了,研究他寫的啥,然後就加了下呼叫時長,blah...blah。由於我當時剛好參與的是基礎設施的平臺,叫共用平臺,是一個可以提供各種基礎設施服務,申請使用的平臺,我就想著這些東西可是寶貝,意味著我們的框架可以測試他,也可以利用他,於是我加了mysql連線池、加了mongodb,加了casandra等等。其實後面,我還搞了分詞庫,用的搜狗詞庫,但這些有點脫離了框架的本質,所以其實我沒有在框架介紹中包括進去。
隨著加的東西多了,整理了下程式碼,畫個分層結構,比如用例層、業務方法層、公共函數庫、第三方依賴,再加一些紀錄檔裝飾器等等,就挺唬人了,當然,最後這個框架被推廣起來了,我又寫了setup.py,進行打包,放到了自己的映象中管理起來,這樣,大家可以通過指定pip源,就可以更新安裝。
當時框架的介面檔案差不多這樣吧:https://cleardo1986.applinzi.com/html/nd.rest
介面測試框架其實用python來寫,是最沒技術含量的,因為python足夠簡單,庫足夠多,但是大部分測試開發其實是沒多少底子的,有些是測試兼職寫程式碼的,所以就挺適合他們。
輪到UI自動化,這裡先說WEB,PC我後面再補充,大部分人做不好PC,其實我感覺方向錯了,因為PC是作業系統強相關,你依賴的是windows的win32 API。(跑題了,逃!)回到WEB UI自動化,當時的王者是selenium,其實現在還是,只不過這破東西,就是一個介面測試框架,他的核心就是牛逼的http連線池,然後去呼叫chromedriver、gekodriver、safaridriver、Edge driver、IE driver。
我自己嘗試編譯了下chromedriver和Edge Driver,你會發現,人家這才是牛逼的程式碼,你直接繞過driver,觸發對應的瀏覽器,穩定性一定會上一個臺階,當然,代價就是這個程式碼普通人看不懂,chromium的程式碼,堪稱行業的C++工程典範,幹測開的,你沒時間去同時維護這麼多,所以,自然而然的,基於selenium來打造一個UI自動化測試框架,就成了唯一的路,通過重試啊、等待啊,勉強能夠發現一些問題。代價就是你要天天去看,為什麼沒跑過,哪裡異常了。框架底層的大部分,都是在折騰這些事。
當然,我這種菜雞,也是折騰這些。一開始,封裝元素定位層,封裝控制元件操作層,只要一個基礎類別就可以搞定了,當時應該是selenium3,就pip安裝下,指定chrome的路徑,寫一個drivermanager的驅動管理類,就可以把流程跑起來了。其實我做UI自動化的時間並不長,因為當時部門的重心還是放在了介面上。當時也沒有pytest、allure這樣的神器,大家對PO模式也是一知半解,所以整個UI自動化測試過程是痛苦的。
後面,來了個叫H2的測試開發大佬,他打字不快,但是編碼邏輯思路很清晰,在測試開發經驗上也很豐富,我記得他的一個理念就是反對在框架中封裝過多的js指令碼,因為對於端到端的測試來說,使用者是不可能去直接執行JS指令碼的,能模擬使用者點選的,還是應該模擬。最後我們組的UI自動化測試框架由他使用java重新寫了一遍,還加上了分散式執行,使用的apache mq,來接收訊息,並觸發用例指令碼。這個架構基本是沒啥問題的,但是穩定性的保證還是需要做不少工作,感覺適用staf這個分散式框架來託管指令碼,應該是個不錯的選擇。總之,我得承認的是,我在WEB UI自動化領域,不算資深,但是在框架的理解上,應該也是正確的,畢竟實踐才是檢驗真理的唯一標準,實踐不夠,只能說我的小腦袋,還是沒法做到真全棧。
不管PC端還是WEB端,其實我們做的前端測試,都可以統稱為2D圖形介面及其互動測試。但是隨著圖形顯示器的快速發展,3D顯示效果和效能都有著十足的飛躍。公司開發了一款3D編輯器軟體,這款軟體是我至今為止看過的內部開發的最複雜的程式碼。
做3D測試,需要在原來的2D介面增加一個Z軸,除了這個區別,其實測試點和原來的軟體沒啥區別。但是這個Z軸在很多方面增加了複雜性。原來的座標操作,包括平移、旋轉、縮放,包括一個攝像機位置,都需要專門處理。這裡面涉及齊次座標,尤拉角、四元數等複雜的概念。如果你是黑箱測試,你靠想象力測試也沒啥問題(所以,黑箱測試比白盒測試就是簡單在這裡,你只有思維發散,專業理論不懂,也沒什麼關係)。不過,我一般不會滿足於單純的黑箱測試,所以我把這款3D軟體涉及到的知識整理了下,大致可以分為遊戲邏輯GameLogic、物體變換、顏色、光照、動畫、粒子系統、紋理、碰撞、外設事件處理等部分,其實綜合來看就兩個大塊,一個叫渲染系統、一個叫物理引擎,其中渲染的核心就是著色器Shader,我們公司有個崗位叫TA,也叫技術美術,就是專門研究這個渲染系統,算是美術和技術的橋樑吧。這個編輯器的開發原理,就是把Unity提供的各種能力,進行封裝後,通過視覺化操作,開放給使用者,有點類似Minecraft。
對於這種編輯器型別的應用,使用者使用場景繁多,基本沒法遍歷,因為是模型+行為的指數級,所以只能進行對偶pairwise或者正交表來設計用例。這裡推薦機個很強大的工具,一個是微軟的PICT,可用於生成pairwise用例,另一個是自動化操作模擬工具AHK,可以模擬windows上的按鍵操作,用來代替人工在PC端上點點點。通過這些工具,我們設計了一些用例組合,在這個3D編輯器上編輯後,打包生成一個可以執行的場景,但是,這個場景的效能問題很大,到底什麼原因卡,比較難判斷。我們當然希望能夠把根因儘量分析清楚,我的排查思路是先對編輯器新增的所有的GameObject進行一次遍歷,並確定其型別,然後逐步的把各種特效給去掉,這個過程需要有點耐心,在逐步分析後,我們發現,有很多不必要的特效被加了進去,比如加了多個多餘的光源,還有一些地形的疊加、樹木Entity(包括大量的樹葉頂點),其實都是比較影響效能的。雖然U3D自身也替我們做了許多工作來幫助優化效能,比如攝像頭畫面部分渲染、遮擋剔除等,但是開發過程中,如果不注意對資源的使用,或者進行一些過度的計算,都會導致卡頓問題。
最後,其實資源一般都需要進行專門的檢測,比如面片數、頂點數,我通用C++的一個assimp模型匯入庫來進行一些模型的載入分析,然後放到自己的scene中,去觀看效果。對於我這種非專業開發來說,喜歡用樸素的實現方式可以讓我清楚地知道我每一步到底在幹什麼。
因為已經研究過一段時間的3D相關知識,剛好又趕上國家在大力扶持VR產業,都說一流的企業座標,二流的企業做產品,這時工信部電子技術標準化研究院的王聰老師,剛好在負責相關的標準化工作。標準雖然不是強制性標準,但是對於企業來說,能參與進去,還是能起到一定的宣傳作用。所以在領導的鼓勵下,我們就積極報了名,並和王聰老師聯絡上,開始參與進這個標準的起草工作。
國家標準整個制定過程可比企業內部標準嚴格得多,國家標準的規定,除非是食品、安全相關,大都是指導性的,因為很多標準很難去統一量化,特別是軟體行業,不同類別的應用,其實開發過程差異相當大,基本不大可能統一化。所以我們看GB/T 25000之類的,就是列指標和度量維度。所以在起草這個標準時,多次召集國家科研院校的專家老師和各大公司的技術大牛進行激烈討論。最後,還是基於測試模型來進行定義,包括功能、效能、易用、可靠、易維護、可移植、相容方面來對VR軟體進行測試指標和方法的說明。這個標準的起草,其實對企業的測試意義可能不是很大,因為測試方案的制定,沒有人會離開這幾個維度,但是脫離標準進行測試,本身就是不對的行為,你可以圍繞國標,去制定自己內部的一些標準規範,標準定出來了,才能執行測試,不然,根本不知道測試到底通沒通過。而不是單純為了配合開發,去拍腦袋,這其實對使用者是很不負責的,只能說,專案的壓力還是太大了,有時為了按時交付,就選擇走捷徑了,帶傷釋出。不過,對於國家而言,標準的意義其實是很重大的,比如有一類標準是關於技術細節定義的,類似OpengGL這樣的,如果能夠對這個技術細節進行充分完整的定義,那麼我們在開發3D應用時,就可以都統一使用國家的標準格式,一個是涉及智慧財產權問題,一個就是國家內部各個平臺的打通問題,如果標準寫得不清晰,存在歧義,那麼對以後國家專案的建設就會帶來很多不必要的麻煩。
總的來說,標準最重要的是標準化的物件定義要清晰,你要標準化的物件邊界一定要先劃分清楚,然後才能圍繞這個物件建立起標準體系,要做到邏輯嚴謹,一環扣一環,如果不是行業專家,真的做不來這個。最後說下,我即使參與了這個標準的起草,其實遠稱不上專家,專家的經驗、經歷、技術一定要達到一定的積累,而企業中大都比較浮躁,畢竟盈利和生存才是最重要的。但是無論如何,在參與過程中,認識了很多的行業大牛,知道了自己和專家老師們的差距,這點上對我個人還是很有收穫的。
其實我平常是不喜歡玩遊戲的,玩遊戲其實是很難的事情,一個是要動腦,還一個是要動手,比你寫程式碼還難,寫程式碼就是按順序敲著字母和標點符號,但是玩遊戲,特別是對戰遊戲,需要涉及到策略、操作、共同作業等等。能夠對遊戲進行測試,也算是對自己的一個挑戰吧。除了測試,還想要加點AI的東西,這個靠我一個人肯定是搞不定的,當時我們是幾個人進行了下分工,有個熱愛AI的量化大牛TS,顏值與才華並存的研究生美女,還有一個大氣豪放的周董。我們基本安裝遊戲操作庫封裝、影象識別、演演算法研究進行了分工。在這裡面,我更多還是打個雜,因為對神經網路是完全的小白,不過,在做這個專案的過程中,還是算入了個門,學會了keras、QLearning的模型的使用,還用了下tessert的OCR庫,最後在把同事訓練好的yolo v5的模型導進來,在自動跑指令碼的過程中,識別英雄人物後,進行一些操作,把棋局狀態記錄下來,設計血量為reward獎勵,不斷的學習對戰策略。總體來說,這個專案沒有達到預期的效果,就是對戰能力幾乎就是3歲小孩子的遊戲水平。但是,我其實意識到,遊戲算是一個狀態機,只不過狀態比較複雜,不考慮遊戲情節推進的話,能夠在debug模式下,把具體的狀態抽象記錄下來的話,很多遊戲還是可以AI化的,只不過這個對大多數人來說,門檻確實太高了。
隨著年紀的變大,部門人事變動,在專案中做測試技術的歸屬感其實是相對較弱的,因為專案的考核更多的會圍繞BUG產出,用例執行,對於專案方來說,其實是接觸不到,也感知不到測試開發的存在的,也就是說測試開發在部門層面可能很重要,但是在專案團隊,其實很難達到核心的層次。因此,我有時也嘗試著去當一個測試leader的角色,為了瞭解相關的專案管理和團隊管理知識,我考到了pmp證書和scrum證書,基本上我參與的考試都是拿到了優秀,但相比研究測試工具來說,學習還是付出了較大的努力,通過的時候有那麼一點小激動吧。管人管專案,其實是很累的一件事,我其實有時會比較缺乏自信(當然,我也不懂很多人的自信是怎麼建立起來的)。當時對測試管理而言,我最怕的就是漏測,每次出線上問題,總是緊張得不行,當時我負責的是基礎設施的專案,對高可用要求非常嚴格,而且還碰上了機房遷移,通宵了幾個晚上,還是出了一些問題,因為涉及的元件顆粒實在是太多了,包括公司的所有軟體專案,也導致我當月績效被降了一檔。我最痛苦的還有評下屬的績效,因為公司規定,是需要有績效比例分佈的,所以每次都會評出一些不好的人出來,然後就需要面談,請喝下奶茶,緩和一些上下級的關係。在我們公司內部,會提供很多管理類的培訓,比如其中一個叫「潛龍七式」,裡面包括目標制定、任務派發,績效面談、員工反饋、插單處理、覆盤等等,但是學完後,在實際應用中還是缺乏刻意的練習和使用這些技巧來幫助管理。
總的來說,測試管理是一項對溝通技能要求非常高的工作,更多的是偏文科類的,比如要建立質量體系,梳理流程規範,做好質量資料度量分析、以及牽頭進行質量相關的覆盤總結工作,進行PDCA,持續改進等等。
這裡的效能是指的伺服器端效能,在伺服器端除了linux,其實我瞭解的並不多,因為從事伺服器端開發,其實是10年前的事,如今Spring成了這一領域的王者,但是因為個人精力原因,一直沒有投入時間去折騰這個,可能偶爾專案需要的時候,在idea上跑一跑,改一改舊的程式碼。不過作為QA來講,伺服器端測試和安全測試應該是最有難度的兩個部分。所以在公司效能測試人才流失的情況下,我自然而然的開始也學著做起了效能測試,在一個效能測試過程中,一般會包括效能需求分析、造數、效能指令碼開發、效能負載機部署、執行效能指令碼,收集效能測試結果並分析瓶頸,最後提供測試報告。
我在需求分析的時候,一般會找到業務架構師、開發負責人確認好這個系統的業務規模,比如是一個新的系統,還是在原有系統上的改進優化,這樣我們才好確認壓測的目標、造數的策略、測試時關注哪些指標等等。
造數是我覺得在介面壓測過程中最為繁瑣和討厭的地方,因為我們這裡專案用的服務太多了,有mysql、mongodb、redis、es、hbase、tidb,cassandra,在壓測過程中,需要有一定的資料量打底,但是你如果單純的插入資料,那可太耗時了,所以造數一般還是得依靠壓測工具,這個環節其實我做得並不好,有時我就是找開發、找運維一起幫忙導資料進去,我一般會按照格式要求,寫入到一些如json或者csv的檔案,然後就交給他們,大公司裡流程很規範,只要下個單,能夠算好成本就好了。
我們用的是nGrinder,底層就是Grinder,這個平臺支援jython指令碼開發壓測指令碼,所以寫指令碼對我難度其實不大,就是把指令碼提供的API給熟悉了就行,但是這裡遇到了一個問題,在平臺上偵錯指令碼,真是太太太卡了,如果你模板改的不多,那就還好,如果你模板改動很大,那偵錯起來就相當耗時,所以我自己開發了一個grinder的模擬器,其實就是把他的API,線上下自己模擬了一遍,把他的HttpRequest改成了httplib,然後一堆header、response解析,按照格式重新寫了下,這下偵錯指令碼可快樂了,因為速度快了好幾倍,再也不同經歷漫長的等待了。但是,同時這也有個好處,就是遇到在伺服器上跑不過,本地卻跑過的時候,不好排查,因為環境只要有差異並且是你沒有意識到的,就會誤導到自己,比如,我就遇到一個因為header裡的app-id其實不一樣,但是我忽略了這個,導致和伺服器上的結果不一樣,排查了半天,因為我在遷移指令碼時,把這個設定給漏了,並且只列印了body,沒有考慮header,犯了這個低階錯誤,還好有效能組同事幫忙提醒了下。
負載機部署:grinder的部署應該是相對簡單,主要是把代理指令碼上傳到每一臺機器上,因為我使用的機器其實並不多,所以我其實沒有去制定對應的自動化分發代理的方案,而且我們使用的虛擬機器器平臺需要通過堡壘機專用的運維繫統來存取,並且虛擬機器器一般不會反覆部署。理論上,是部署一臺,複製過去就可以了。
因為是在nGrinder上執行指令碼,所以只要設定好VUSER的數量和並行遞增策略,就可以開始跑了,因為我們是用的falcon收集伺服器資源資料,所以在跑的過程中,只要確認壓力有打進去,並行生變化,就可以了,如果是做的線上壓測,還需要判斷是否需要進行資料環境的隔離,避免汙染正式資料,影響了一些業務資料統計和分析。
結果分析一般就依靠對應的圖示,比如是否有突刺,報錯紀錄檔,最好能夠結合pinpoint進行一些問題的定位,如果是資源佔用問題,那就比較好定位,如果資源佔用一切正常,那麼可能就發生了一些諸如死鎖,或者一些錯誤結果被提前返回的情況,因為為了保證系統的穩定性,伺服器端其實會對異常做了很多降級處理,這種情況,其實TPS和響應時間都正常,但是報錯率也會比較高。
這裡針對的是http型別的請求,如果是websocket或者gRpc這類的,可能grinder就不是很適合,即使改造了,結果也不一定滿意。
首先,真的會老,所以公司很難成為你的家,除了體制內,等你老了,這個家可能就容不下你,這很正常,因為當這個家不能給你提供糧食時,你也會選擇放棄,對不對?
其實不管是不是技術,除非自己的人脈能夠一直穩定持續維護,不然都是會出現問題的。
所以你能做的,就是要麼選擇低壓力的環境快速成長,或者就選擇高壓環境默默忍受,當然最理想的就是實現專案和成長的正向迴圈,比如,你在這個專案學到了自己想要學到的,你獲得了成就感,同時專案也做大做強了。其實,就是詩和遠方都有了。
測試開發其實能夠深入瞭解程式語言的機會並不多,因為在工作中涉及太多的工具和新知識,並且因為經常是在進度壓力下要求二次開發交付,很多時候,我其實是憑著感覺在定位程式碼,並靠著百度,把自己的想法給實施了。但是任何技能,都是熟練到肌肉記憶才能夠成為專家的級別。對於測試開發而言,能夠得到這種機會的並不多,因為經常需要兼顧測試和小工具開發,除非是有專項研發的部門,並且遇到特別穩定的專案,可以讓你長期專注某個領域。
我在幾年的工作中,接觸的程式語言就有php、python、java、c、c++、C#、javascript、es6、typescript,接觸這麼多,導致的一個問題就是很多語言用著用著就忘記了,涉及的生態體系,也基本沒有機會深入研究,比如像Spring,其實包括非常非常多的體系,但是這麼多年來,其實我也沒啥機會鑽研進去。
在一家公司待久了,最大的可能就是不會被頻繁的換環境,投入大量時間去熟悉業務和一堆很類似的框架,十年來,因為每年都會制定一些測試目標,服務不同的專案,所以有機會學習各式各樣的技術,就是知識面可能會比較廣,但是也有缺陷,就是程式設計技能,如果是語言強相關的,那麼就可能出現經驗不足的情況。有人說在大公司,一個蘿蔔一個坑,只會守在自己的一畝三分地。可能幾年前業務好的時候是這樣,但是近幾年,大環境很糟糕,專案倒了一個又一個,但是好在我能夠有一定的自主權,所以我還是能夠堅持自己的人生規劃,畢竟在我看來,幹得久,比賺得多更重要。