北大李戈團隊提出大模型單測生成新方法,顯著提升代碼測試覆蓋率
單元測試是軟件開發流程中的一個關鍵環節,主要用于驗證軟件中的最小可測試單元,函數或模塊是否按預期工作。單元測試的目標是確保每個獨立的代碼片段都能正確執行其功能,對于提高軟件質量和開發效率具有重要意義。
然而,大模型自身無力為復雜待測函數(環復雜度大于 10)生成高覆蓋率的測試樣例集。為了解決該痛點,北京大學李戈教授團隊提出一種全新的提升測試用例覆蓋率的方法,該方法借助程序分片思想(Method Slicing),將復雜待測函數依據語義拆解為若干簡單片段,進而讓大模型為各個簡單片段分別生成測試樣例。生成單個測試樣例時,大模型只需分析原待測函數的一個片段,分析難度減小,生成覆蓋該片段的單元測試難度隨之減小。由此推廣,提升整體測試樣例集代碼覆蓋率。
相關論文《HITS: High-coverage LLM-based Unit Test Generation via Method Slicing》近期被 ASE 2024(at the 39th IEEE/ACM International Conference on Automated Software Engineering)頂會接受。
論文地址:https://www.arxiv.org/pdf/2408.11324
接下來看看北大團隊論文研究的具體內容:
HITS 使用大模型進行程序分片
程序分片指將一個程序依據語義劃分為若干解決問題的階段。程序是對一個問題解決方案的形式化表述。一個問題解決方案通常包含多個步驟,每個步驟對應著程序中的一片(slice)代碼。如下圖所示,一個色塊對應著一片代碼,也對應著一個問題解決的步驟。
HITS 要求大模型分別為每個代碼片設計可以高效覆蓋它的單元測試代碼。以上圖為例,當我們得到如圖的分片后,HITS 要求大模型為 Slice 1(綠色),Slice 2(藍色),Slice 3(紅色)分別生成測試樣例。為 Slice 1 生成的測試樣例要盡可能覆蓋 Slice 1,不用考慮 Slice 2 和 Slice 3,其余代碼片同理。
HITS 起效的原因有二。其一,大模型要考慮覆蓋的代碼量降低。以上圖為例,為 Slice 3 生成測試樣例,則只需考慮 Slice 3 中的條件分支。要覆蓋 Slice 3 中的某些條件分支,只需在 Slice 1 和 Slice 2 中找尋一條執行路徑即可,無需考慮該執行路徑對 Slice 1 和 Slice 2 覆蓋率的影響。其二,依據語義(問題解決步驟)分割的代碼片有助于大模型掌握代碼執行中間狀態。為順序靠后的代碼塊生成測試樣例,需要考慮先前代碼對程序狀態的改變。由于代碼塊依據實際問題解決步驟分割,因此可以用自然語言對先前代碼塊的操作進行描述(如上圖中注釋部分)。由于當前大語言模型多為自然語言與程序語言混合訓練產物,良好的自然語言概括可幫助大模型更精準掌握代碼對程序狀態的改變。
HITS 使用大模型進行程序分片。問題的解決步驟通常為帶有程序員主觀色彩的自然語言表述,因而可以直接利用自然語言處理能力超群的大模型。具體而言,HITS 使用上下文學習方法(In-context learning) 調用大模型。團隊利用過往在真實場景實踐的經驗,手工編寫若干程序分片樣例,經若干次調整后使大模型對程序分片的效果達到了研究團隊的預期。
對代碼片生成測試樣例
給定要覆蓋的代碼片段,要生成對應測試樣例,需經歷以下 3 個步驟:1. 對片段的輸入進行分析;2. 構造 prompt 指示大模型生成初始測試樣例;3. 使用規則后處理和大模型 self-debug 調整測試樣例使之可以正確運行。
對片段的輸入進行分析,指提取要覆蓋的片段所接受的一切外部輸入,以備后續 prompt 使用。外部輸入,指該片段所應用到的先前片段定義的局部變量,待測方法的形參,片段內調用的方法以及外部變量。外部輸入的值直接決定了要覆蓋的片段的執行情況,因此將該信息提取出來提示給大模型有助于有針對性地設計測試樣例。研究團隊在實驗中發現大模型擁有良好的提取外部輸入的能力,因此在 HITS 中由大模型來完成該任務。
接下來,HITS 構建思維鏈(Chain-of-thought)形式的 prompt 引導大模型生成測試樣例。推理步驟如下。第一步,給定外部輸入,分析要滿足待覆蓋代碼片內的各種條件分支的排列組合,外部輸入都分別需要滿足哪些性質,如:組合 1,字符串 a 需要包含字符’x’,整數變量 i 需要非負;組合 2,字符串 a 需要非空,整數變量 i 需要為質數。第二步,對上一步中的每一種組合,分析相對應的待測代碼執行時所處環境的性質,包括但不限于實參的特性,全局變量的設置。第三步,為每一種組合生成一個測試樣例。研究團隊為每一步手工構建了樣例,以便于大模型能夠正確理解并執行指令。
最后,HITS 通過后處理和 self-debug 使大模型生成的測試樣例得以正確運行。大模型生成的測試樣例往往難以直接使用,會出現各式各樣的編譯錯誤和來自于錯誤編寫測試樣例導致的運行時錯誤。研究團隊根據自身觀察及已有論文的總結,設計了若干規則和常見錯誤的修復案例。首先嘗試依據規則修復。如果規則無法修復,則使用大模型 self-debug 的功能進行修復,在 prompt 中提供了常見錯誤的修復案例以供大模型參考。
HITS 的整體圖解
實驗驗證
研究團隊使用 gpt-3.5-turbo 作為 HITS 調用的大模型,分別在大模型學習過和未學習過的 Java 項目中的復雜函數(環復雜度大于 10)上對比 HITS,其他基于大模型的單元測試方法和 evosuite 的代碼覆蓋率。實驗結果顯示 HITS 相較于被比較的諸方法有較明顯的性能提升。
研究團隊通過樣例分析展示分片方法如何提升代碼覆蓋率。如圖所示。
該案例中,基線方法生成的測試樣例未能完全覆蓋 Slice 2 中的紅色代碼片段。然而,HITS 由于聚焦于 Slice 2,對其所引用的外部變量進行了分析,捕捉到 “如果要覆蓋紅色代碼片段,變量’arguments’ 需要非空 “的性質,根據該性質構建了測試樣例,成功實現了對紅色區域代碼的覆蓋。
提升單元測試覆蓋率,增強系統的可靠性和穩定性,進而提高軟件質量。HITS使用程序分片實驗證明,該技術不僅能大幅提升整體測試樣例集代碼覆蓋率,且實施方法簡潔直接,未來有望在真實場景實踐中,幫助團隊更早發現并修正開發中的錯誤,提升軟件交付質量。