基於 AI 大模型的精準測試分享

AMEAME發表於2024-04-23

一、問題提出

  1. 如何使用大模型解決日常工作中難以解決的問題?

  2. 大模型在自動化測試領域可以發揮什麼作用?

  3. 如何利用大模型提前發現故障,並提升產品質量?

  4. 如何發現日常工作中難以察覺的故障?

團隊現狀:

A. 經常性的洩露一些修改 java 依賴引發的故障,在 maven 的 pom.xml 檔案中修改一個依賴的版本號都可能引出故障,見下圖例子

此型別的問題難以發現的原因:

  • 方案層面:評估此類版本依賴修改成本較高,因為一項依賴的修改可能牽扯很多程式碼;
  • 開發層面:因修改 pom.xml 檔案依賴版本號操作小,無程式碼邏輯修改,開發自測場景不完整;
  • 測試層面:QA 不瞭解具體程式碼和波及影響,很難確定測試範圍,不知道哪些功能需要使用這些依賴;
  • 自動化層面:透過自動化掃描異常日誌,日誌中存在大量干擾,導致自動化異常掃描精度不高;
  • 成本高:即使評估出測試功能點,方案評估,開發實現,測試驗證整個流程成本較高。

B. 沒辦法對所有的新增程式碼進行 CodeReview,Review 的效果一般,容易洩露在功能測試階段無法發現的問題。

因此,針對上述原因,將大模型與當前自動化測試相結合,透過大模型自動化來防護此類問題就是本實踐的目標。

二、解決思路

雖然該類問題難以發現,但也並不是毫無辦法。

該類問題有個共同點:在 JVM 執行時,找不到某個依賴,會丟擲:ClassNotFoundException,NoClassDefFoundError,IllegalAccessException,InstantiationException,NoSuchMethodError 等異常。

那我們收集到元件日誌後是否就能規避這種問題呢?

答案肯定是不行的。舉個例子:

例如團隊內元件熱部署探針執行在框架中,在熱部署探針啟停階段,因探針在框架中提交的執行緒還在輪詢,探針例項已經被銷燬後,依舊會出現很多上面的異常來干擾判斷,無法得出精確的結果,所以需要從提升精度的方向去最佳化。以下是思考方向:

  1. 故障多出現於程式碼修改前後。
  2. 不同分支程式碼的差別可能導致新故障的出現。

如何去解決呢,想了以下幾點:

  1. 如果能獲取到 git 上面的程式碼提交記錄,就能收集到熱點程式碼。
  2. 能拿到不同分支程式碼的變化,就能收集到另一部分的熱點程式碼。

然後還有最重要的一點,收集的異常資訊和熱點程式碼的對映如何建立呢?如果手動去建立 異常->依賴 的對映始終會滯後,出一次問題加一次不利於可持續發展,而且只有當在出問題時才能知道丟擲的異常長什麼樣,難以完成該專案。

所以引入了大模型去幫我完成 異常->依賴 的建立。

三、實踐過程

架構概述

實踐過程採用了以下架構:

  1. 資料來源層:專案元件執行在大環境下,利用大環境提供的基本資料來源。
  2. 程式碼變更獲取層:從 Git 倉庫中獲取程式碼變更資訊,包括同分支增量對比和不同分支全量對比。
  3. 日誌處理層:透過日誌收集模組處理元件日誌,提取異常資訊。
  4. AI 大模型互動層:向 AI 大模型提出針對性問題,並解析其回答。
  5. 結果處理與輸出層:根據 AI 大模型的回答在快取中尋找熱點程式碼,記錄日誌,併傳送郵件通知對應處理人。

針對 pom.xml 的實踐步驟

  1. 獲取大環境資料來源:專案元件執行在大環境下,利用大環境提供的資料來源進行後續操作。

  2. 獲取程式碼變更

    • 從 Git 中獲取 XX 專案 XX 分支的 XX 個提交記錄。
    • 遍歷每個提交記錄,獲取修改的檔案列表。
    • 過濾出 maven 依賴型別的檔案(如 pom.xml)。
  3. 解析修改檔案

    • 對修改的檔案進行分類處理,包括只增、只減、修改三種型別。
    • 解析出程式碼修改內容,並將其快取起來,作為熱點程式碼。
  4. 日誌處理

    • 透過日誌收集模組下載元件例項的日誌檔案(包括.log 和.gz 格式)。
    • 解壓 gz 格式的日誌檔案,並將不同例項的日誌進行彙總。
    • 將日誌按照級別(info, warn, error)進行分類。
    • 提取 warn 和 error 級別日誌中的異常堆疊資訊。
    • 對堆疊資訊進行去重處理,減少後續處理的冗餘資料。
  5. 與 AI 大模型互動

    • 根據提取的異常資訊,向 AI 大模型提出針對性問題。
    • 解析 AI 大模型的回答,獲取可能的故障原因或解決建議。
  6. 熱點程式碼匹配與記錄

    • 使用 AI 大模型的回答在快取的熱點程式碼中尋找相關匹配項。
    • 如果找到匹配項,記錄相關日誌資訊,包括匹配的熱點程式碼和異常資訊。
  7. 傳送郵件通知

    • 將記錄的日誌資訊整理成郵件格式。
    • 傳送郵件到對應處理人的郵箱,通知其關注並解決相關問題。

針對 java 檔案的實踐步驟

  1. 獲取大環境資料來源:同樣利用大環境提供的資料來源。

  2. 獲取指定需求編號的程式碼變更

    • 從 Git 中獲取指定需求編號的提交記錄。
    • 遍歷每個提交記錄,獲取修改的檔案列表。
    • 過濾出.java 檔案。
  3. 解析修改檔案

    • 對修改的.java 檔案進行類似 pom.xml 的解析操作。
    • 分類處理只增、只減、修改的程式碼,並快取熱點程式碼。
  4. 與 AI 大模型互動

    • 根據需求背景和修改內容,向 AI 大模型提出針對性問題。
    • 解析 AI 大模型的回答,獲取可能的程式碼風險或最佳化建議。
  5. 結果輸出

    • 將 AI 大模型的回答或解析結果輸出到檔案中,便於後續檢視和分析。

透過上述實踐過程,可以有效結合 AI 大模型與自動化測試技術,提升故障發現和產品質量的能力。同時,減少了人工審查和測試的工作量,提高了工作效率和準確性。

效果評價

針對 pom.xml 如下:

  1. 執行自動化測試用例,測試用例會從 git 庫中獲取指定專案指定分支的程式碼提交記錄,進行解析和快取。

    • 在程式碼配置每個標籤中的子標籤,如需解析其他的標籤,則新增一個標籤類並重寫查詢該標籤的正規表示式
    • 按照新增或刪除的配置和修改的配置(修改可能只會改一個結構體的一部分,需要找到對應完整的結構體)進行解析
    • 快取解析結果
  2. 收集環境上日誌,拿到原始日誌後進行分類

    • 先把容器內的日誌複製到節點上,透過 SSH 協議把日誌下載到執行環境。元件可能有多個例項,獲取所有例項日誌。
    • 把 GZ 日誌包進行解壓,對日誌內容進行分類(info, warn, error),按照配置檔案配置的異常型別在 warn 和 error 日誌中進行查詢
    • 可能某些異常日誌會很多(幾個 G 日誌),不方便檢視,所以下面進行去重。
  3. 透過一些對字串的演算法,把 java 異常堆疊進行去重,同種型別的異常只保留一個,方便人工檢視和郵件推送

  4. 把解析好異常堆疊向大模型提問,自定義模板的大模型提問見下:
    出現以下異常是缺少什麼 maven 依賴: java.lang.ClassCastException: XXXXXX

大模型回答:
這個問題可能是由於你的專案缺少了 CGLIB 庫引起的。你可以嘗試在你的 pom.xml 檔案中新增以下依賴:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>  <!-- 你可以選擇需要的版本號 -->
</dependency>

然後執行 mvn clean install 以重新構建你的專案並下載所需的依賴

  1. 解析出答案中的依賴 groupId 和 artifactId 等關鍵欄位,把解析出的依賴在熱點程式碼中查詢,找到了說明大機率引出故障!

針對 java 檔案的自動化大模型 CodeReview

實踐過程

1. 執行自動化測試用例

測試用例會從 git 庫中獲取指定專案指定需求編號的程式碼提交記錄,進行解析和快取。

  • 把每個 java 檔案拿到後,把程式碼解析成抽象語法樹(AST)。
  • 依次解析各個節點,如 Class, Package, Import, Implement, Constructors, Field, Method 等。
  • 對解析結果進行快取,以便後續快速訪問。

2. 併發請求 AI 大模型進行 CodeReview

獲取需要使用的 Method 資訊,以最大併發 20 的限制去請求 AI 大模型。以下是 prompt 模版的示例:

## 角色: 程式碼評審專家

## 背景: 你是一位java語言專家級工程師,具備出色的程式碼審查能力,能夠從多個方面評審程式碼。

## 任務: - 對指定程式碼進行系統化地審查。
## 任務細節: 對程式碼能夠從以下方面進行逐一審查:
- 邏輯漏洞:評審程式碼邏輯是否有缺陷。遵守要求:排除因為沒有判空而導致的空指標異常等,不評審因沒有判空等而導致的漏洞,不進行入參為空的校驗。
- 程式碼結構:評審程式碼結構是否清晰、易於理解,變數和函式的命名是否規範。
- 函式實現:評審函式實現是否正確、高效、安全,是否存在潛在的記憶體洩漏。
- 異常處理:評審異常處理機制是否完善,是否存在可能引發異常或崩潰的程式碼。
- 資料結構:評審程式碼中使用的資料結構是否合理,是否能滿足實際需求。
- 效能最佳化:評審程式碼中是否存在效能瓶頸,是否有不必要的計算和呼叫等問題,是否可以進行最佳化。
- 資源洩露:評審程式碼中是否存在資源洩露,是否有檔案流、執行緒池等未關閉情況。
- 安全性:評審程式碼中是否存在安全漏洞,是否有防止SQL隱碼攻擊、XSS攻擊等安全機制。
- 可讀性:評審程式碼是否清晰易於讀懂,註釋是否充分、準確、規範。
## 任務輸出: 評審程式碼存在的問題,並輸出程式碼風險等級
## 待評審程式碼
[這裡插入待評審的Java方法程式碼]

3. 寫入評審結果

把 AI 大模型返回的 CodeReview 結果寫入檔案,方便後續檢視和分析。

評審結果

程式碼走查報告
一、邏輯漏洞

在XXX方法中,XXXList values = new XXXList();被初始化為一個單例,然後在多執行緒環境下被多個執行緒共享。這可能導致執行緒安全問題,因為多個執行緒可能同時修改values的內容。根據方法內的使用情況來看,每個執行緒應該處理自己的XXXList例項,而不是共享一個。

countDownLatch.await();在呼叫時未設定超時時間,如果某個執行緒因為異常或其他原因未能執行countDown,那麼主執行緒將永遠等待下去,造成程式阻塞。

二、程式碼結構

程式碼結構基本清晰,但是使用了裸執行緒池和CountDownLatch,使得程式碼在併發控制上稍顯複雜。建議使用更高階的併發工具,如CompletableFuture,以簡化程式碼。

變數命名較為規範,但XXX方法作為lambda表示式中的匿名內部類呼叫,其引數列表過長,可以考慮封裝成物件來傳遞。

三、函式實現

executor.submit中捕獲了所有異常,但只是列印了日誌,沒有重新丟擲或者對異常進行處理,這可能會導致呼叫者無法得知操作是否成功。

使用了CopyOnWriteArrayList來作為結果集合,這個資料結構適合讀多寫少的場景。然而,在本例中,寫操作(新增元素)頻繁發生,這可能會導致效能問題,因為每次寫操作都會複製底層陣列。如果併發寫操作不多,可以考慮使用其他併發集合,如ConcurrentLinkedQueue。

四、異常處理

異常處理機制不完善,如上所述,捕獲異常後只是列印了日誌,並沒有合適的錯誤處理邏輯。
五、資料結構

CopyOnWriteArrayList的選擇可能不是最佳的資料結構,如上所述,它可能不適合寫操作頻繁的場景。
六、效能最佳化

由於使用了CopyOnWriteArrayList,且寫操作頻繁,可能會導致效能問題。建議考慮其他資料結構或併發控制策略。

執行緒池中的核心執行緒數設定為1,可能無法充分利用多核CPU資源,如果處理邏輯不是IO密集型的,考慮增加核心執行緒數。

七、資源洩露

程式碼中建立了執行緒池,但未在方法結束時關閉執行緒池。這可能導致資源洩露,因為執行緒池會一直存在,即使方法執行完畢。建議在方法結束時關閉執行緒池,或者使用try-with-resources語句(如果執行緒池實現了AutoCloseable介面)。
八、安全性

程式碼中未看到明顯的安全漏洞,如SQL隱碼攻擊或XSS攻擊,但需要注意XXX和XXX方法內部是否有可能引入安全問題。
九、可讀性

程式碼整體可讀性較好,但併發控制和異常處理部分可以進一步簡化,以提高可讀性。
程式碼風險等級

綜合上述評審,程式碼存在邏輯漏洞、資源洩露等問題,風險等級評定為中等偏高。建議對上述問題進行修復,以提高程式碼的健壯性和效能。

這段程式碼執行緒洩露的問題當時沒有測試到,從而在春節的時候洩露到外場去了😂 ,導致開發在春節還在排查問題。
還有一個問題是在修改後,透過大模型評審發現的,就是方法中 new 了個非執行緒安全的 List,並且執行緒池提交的多個執行緒都傳入了這個 List,在處理邏輯中又進行了 add 的操作,所以可能會導致資料最後 add 少了或者直接丟擲異常。

這些問題雖然很基礎,但是如果沒有進行程式碼走查,其實透過黑盒測試很難發現這兩個問題,還是體現了該工具產生的價值!

4. 推送郵件

把評審風險為中或者高的結果推送到相關人員進行進一步的人工評審。

優勢與效果

透過自動化進行大模型 CodeReview,可以顯著減少人工審查的時間和成本,提高程式碼質量和安全性。在分鐘級的時間內就能完成需求或故障修改的大模型 CodeReview,極大地提升了開發效率和程式碼穩定性。同時,透過併發請求 AI 大模型,可以充分利用計算資源,進一步提高審查速度。

相關文章