引用
Messaoudi, S., Shin, D., Panichella, A., Bianculli, D., & Briand, L. (2021). Log-based Slicing for System-level Test Cases. In 2021 ACM SIGSOFT International Symposium on Software Testing and Analysis (ISSTA).
摘要
回歸測試是軟件測試中最重要的活動之一。然而,如果複雜系統測試用例設計糟糕,它的成本效益和實用性會大大降低,并且需要大量的時間和資源來運行測試。緩解這個問題的一種方法是将系統測試用例分解成更小的、獨立的測試用例——每個測試用例隻有一個測試場景和斷言——每個測試用例的執行時間就比原始的測試用例低,同時原始測試用例的測試有效性被保留。這種分解可以通過程序切片技術來實現,因為測試用例也是軟件程序。然而,當(1)測試用例使用外部資源,(2)代碼檢測不是一個可行的選擇,以及(3)測試執行代價昂貴時,現有的靜态和動态切片技術就會有很大的局限性。
本文提出了一種新的分解系統測試用例的方法 DS3(Decomposes System teSt caSe),該方法可以自動将一個複雜的系統測試用例分解為獨立的測試用例切片。其思想是使用測試用例執行日志來識别由靜态切片生成的切片中“隐藏”的依賴關系。由于日志包含關于被測試系統的運行時信息,我們可以使用它們來提取全局資源的訪問和使用,并細化由靜态切片生成的片。
我們評估了 DS3 的切片效率,并将其與普通的靜态切片工具進行了比較。我們還将 DS3 得到的切片與相應的原始系統測試用例進行了測試效率和有效性的比較。評估結果表明,DS3 能夠準确地識别與全局資源使用相關的依賴關系。此外,生成的測試用例切片平均比原始系統測試快 3.56 倍,并且在故障檢測有效性方面沒有明顯損失。
引言
回歸測試是對現有代碼庫進行更改時使用的一種質量保證技術。它保證所執行的更改不會損害代碼現有部分和未更改部分的行為。由于被測系統(SUT)的内在複雜性,以及多年軟件開發積累的技術債務,系統測試用例通常包含多個測試場景,并将其合并到一個測試用例中。這些測試通常被稱為迫切測試,會對回歸測試産生負面影響。在我們的工業環境中,迫切測試需要幾個小時才能運行完。然而,如果這種複雜的系統測試用例可以分解成更小的測試用例而不失去它們的測試有效性,那麼分解的測試用例的執行時間将會減少,測試用例優先級的成本效率将會提高。
在本文中,我們将一個複雜的系統測試用例切片成更簡單的用例——提出一種稱為 DS3(分解系統測試用例)的新方法,該方法基于日志的分析來補充靜态切片。由于日志包含關于 SUT 的運行時信息,我們可以使用它們來提取訪問全局資源和執行的動作,在原始系統測試用例中執行每條語句。通過這種方式,我們可以重新構建由使用全局資源定義的語句之間的附加依賴關系。
背景知識
(1)日志。日志是日志條目的序列;日志條目包含時間戳(記錄記錄的事件發生的時間)和日志消息(記錄記錄的事件)。日志消息可以進一步分解為消息模闆,描述事件類型和事件的參數值,這些參數值是在運行時确定的。
(2)靜态切片。靜态切片是一種技術,使用 def-use 分析,隔離一個程序的“切片”,它影響程序中特定語句中一個或多個變量的值的計算。
基于日志的測試用例分解
我們的新方法稱為 DS3,它将包含多個測試場景的複雜系統測試用例分解為多個單獨的系統測試用例,每個測試用例隻包含一個測試場景及其相關斷言子集,同時保留由于使用全局資源而隐藏的依賴關系。因為測試執行日志包括關于被測試系統的運行時信息,我們可以使用它們來提取被訪問的全局資源(例如,文件,數據庫)和執行的動作(例如,讀,寫)在原始(未切片)系統測試用例中執行每條語句。通過這種方式,我們可以重建在運行時由全局資源生成的語句之間的隐藏依賴關系,這些語句沒有被靜态切片标識。
圖 1
DS3 以系統測試用例、測試用例對應的執行日志、全局資源相關的日志消息模闆為輸入;它返回一組切片,每個切片執行一個單獨的測試場景并包含更少的斷言。在我們的運行示例中,DS3 采用系統測試用例 Tsys(圖 1 頂部)及其對應的日志 Lsys(圖 2),并返回理想切片 I1 和 I2(圖 1 中間和底部)。工程師隻需在日志中标記與全局資源相關的日志消息模闆,例如 output.csv。例如,Lsys 中的日志條目 e1 表示對文件 setup.csv 執行了“讀取”操作。因此,通過查看每個消息模闆,例如 read file *,工程師可以輕松識别它是否與全局資源的使用有關。然後,DS3 使用基于日志的分析自動識别 s1 和 s2 之間的隐藏依賴關系,并通過細化靜态切片生成的中間切片來生成 I1 和 I2。
圖 2
我們的方法不需要訪問源代碼。因此,它可以應用于由第三方組件組成的軟件系統。然而,我們需要滿足兩個條件才能應用 DS3:(1)在測試用例中的語句和日志中的消息之間存在可追溯性信息,(2)日志包含一些關于全局資源使用的信息。
算法 1
算法 1 提供了 DS3 的僞代碼。它以系統測試用例 T=<s1,…,sn>作為輸入,其對應的執行日志 L=<e1,…,ek>,以及日志消息模闆集 MTG={mt1,…,mtn}标記為與 L 中全局資源的使用相關;它返回一組分解的測試用例(即切片)D={D1,…,Dj}。
算法 1 包括四個主要階段:(1)基于斷言的反向切片,(2)使用日志對全局資源的 def-use 分析,(3)切片細化,以及(4)切片最小化。反向切片階段從 T 生成靜态切片 D。全局資源定義使用分析階段識别 T 中的語句、L 中與全局資源相關的日志條目以及對後者執行的操作之間的關系,使用 L 和 MTG.然後在切片細化階段使用所得的三元組 Gdu 來細化每個靜态切片 D∈D。最後,切片最小化階段删除 D 中的任何冗餘切片。算法以返回最小化的 D 結束。
實驗評估
我們将 DS3 作為一個 Python 程序實現,使用 Python Program-Analysis 工具包執行靜态切片。我們評估的候選基準滿足以下需求:(1)它包含系統或集成級測試用例,(2)測試用例應該在執行時生成日志,以及(3)測試用例應該訪問/使用全局資源(例如,外部文件,數據庫,遠程資源)。這些要求由一個專有的基準來滿足,以下稱為 Prop,由我們的一個活躍在衛星行業的工業合作夥伴提供。
(1) 切片效果
為了評估切片的有效性,我們在兩個基準上運行 DS3 和基線靜态切片工具,獲得兩組切片測試用例(每個工具生成一個)。我們使用了以下度量:
其中 D 是由給定方法(DS3 或基線)産生的一組切片。在公式中,分子表示不會導緻編譯或運行時錯誤的測試片的數量;分母表示生成的切片的總數。Eff 的取值範圍為 0~1,Eff(D)值越大,意味着所分析的技術在生成不遺漏任何依賴關系的正确切片時更有效。
表 1 報告了我們的方法和基線産生的切片的數量。“System”列表示基準的名稱;列“#Test Cases”指示要切片的原始測試用例的數量;“Total”、“Pass”、“Fail”列分别表示獲得的切片總數、執行時成功通過的測試用例切片數、執行時失敗的測試用例切片數;“Eff(D)”列表示方法的切片有效性。結果表明,靜态切片機的切片效率低于 DS3。
表 1
(2)切片測試用例的效率
我們将生成的測試片的執行時間與原始(非切片)測試用例的執行時間進行了比較。由于測試用例的執行可以改變環境(例如,通過創建或修改一個文件),我們在運行每個測試用例之前重新設置環境,以避免任何不正确的結果。我們将每個測試運行 10 次,以考慮測試執行時間中的不确定性。我們還評估了 DS3 的開銷,DS3 内部階段所花費的平均時間和切片一個給定測試用例的總執行時間,通過測量超過 10 次執行。
表 2 顯示了運行 DS3 生成測試切片的時間,以及執行生成的切片和原始測試用例的時間。更具體地說,列“Others”、“Static”和“Refine”表示執行 DS3 不同階段的平均時間:查找全局資源定義和使用以及最小化步驟(“Others”)、靜态切片(“Static”),切片細化(“Refine”);“Total”一欄表示 DS3 的平均總執行時間;“Slices”列表示 DS3 産生的切片數;“Org”列表示原始(非切片)測試用例的執行時間;列“Sl.Avh”和“Sl.Tot”分别表示切片測試用例的平均執行時間和累積執行時間,其中後者表示為每個單獨的系統測試用例獲得的所有切片的執行時間之和;“Speedup”列表示未切片測試用例的執行時間與切片測試用例的累積執行時間之間的加速比。
表 2
結果表明,對于 30 個測試用例中的 24 個,DS3 生成的測試用例片的累計執行時間比原始測試用例短,平均加速速度為 3.56 倍。
測試用例 PTC30 可以觀察到最大的加速(23.14 倍)。本例中,5 個片的累計執行時間平均為 1004s(≈17 分鐘);相反,執行原始測試用例需要 23231 秒(≈387 分鐘,即超過 6 個小時)。這個很大的差異是由于規避了無關語句的執行:在原始的測試用例中,一個昂貴的過程實際上與測試用例中的其他語句沒有任何依賴關系;實際上,DS3 成功地在它生成的測試用例切片中确定并排除了這個過程。
在剩下的 6 個測試用例中,測試片的總執行時間高于原始測試用例的執行時間。我們觀察到 PTC5 的加速比的最低值(即最高的減速,0.53):原始測試用例的執行時間為 465s,而 DS3 産生的兩個切片的累計執行時間為 874s。為了進一步理解執行時間大幅增加的根本原因,我們手動分析了 PTC5 及其相應的切片。我們發現,對于這種情況,DS3 創建了兩個獨立的測試片段,每個片段都有測試設置代碼的相同副本;執行此設置代碼會占用文本大小寫片段的大部分執行時間。
(3)覆蓋範圍和故障檢測能力
為了度量代碼覆蓋率,我們使用了 Bullseye coverage——一種高級 C 代碼覆蓋率工具,用于提高關鍵系統領域的軟件質量,如工業控制、醫療、汽車、通信、航空航天和國防。接下來,我們使用突變測試來評估原始測試用例和切片之間的故障檢測能力的差異。
對于突變分析,我們使用了 mutate ,這是一個開源的突變測試工具。Mutate 提供了 15 個突變操作符,包括算術、條件、布爾、數字和行删除操作符。我們在計算中考慮了以下變異運算符:(1)邏輯運算符,(2)條件運算符,(3)遞增小數運算符,(4)算術運算符,(5)布爾文字運算符,(6)十進制數運算符。
為了評估 DS3 的切片過程與原始測試用例(組 2)相比,是否沒有影響測試切片(組 1)的故障檢測能力,我們比較了每組殺死的突變體數量。我們用 KO 表示被原始測試用例殺死的突變體集合,用 KS 表示被 DS3 生成的測試切片殺死的突變體集合。
表 3
表 3 報告了原始測試用例和生成的測試片段的代碼覆蓋率。“FunctionCov”和“BranchCov”列分别表示功能覆蓋和分支覆蓋得分;子欄“Total”表示系統源代碼中功能/分支的總數;子列“Org”和“Slices”分别指示了原始測試用例和切片所覆蓋的功能/分支的數量。
在功能覆蓋率方面,原始的測試用例和生成的切片都達到了 61%(1831/2980)。我們觀察到分支覆蓋率的一個非常小的差異:原始的測試用例覆蓋了代碼分支的 42.36%(5736/13541),而生成的切片覆蓋了代碼分支的 42.08%(5698/13541)。
表 4
表 4 為突變檢測結果。對于最初的系統測試用例,有 289 個突變體被殺死。生成的測試片能夠殺死 288 個突變體,正如預期的,這些突變體都被原始的測試用例殺死了。
實際意義
我們認為 DS3 有助于解決兩種問題:assertion roulette 和 eager tests。assertion roulette 是一個帶有多個斷言語句的測試,這使得測試失敗時的根本原因分析更加困難。eager tests 會同時檢查多個不同的功能,這會對測試代碼的可讀性和可理解性産生負面影響。在給定的系統測試用例上執行 DS3 将産生多個片,每個片有更少的斷言語句和一個單獨的測試場景。由于 DS3,原始測試用例的斷言将分布在生成的片上,從而減少了每個片的斷言數量(assertion roulette)。此外,将測試用例分割成獨立的片段有助于解決 eager tests。
盡管 DS3 有不可忽略的開銷,但它隻需要運行一次,因此它對測試成本的影響是有限的。使用 DS3 的優點是生成的片開銷較小。減少測試執行時間是測試用例選擇和優先級确定的目标之一。此外,可以根據設置配置、輸入值或目标功能對測試片進行分組。可以為每個組進一步選擇片,以隻運行最具代表性的測試片,并進一步降低總體測試執行成本。
在測試用例選擇和優先級劃分中使用的兩個常見目标是覆蓋率(最大化)和測試執行(最小化)。開發人員可以使用 DS3 選擇與原始測試用例達到相同覆蓋率和變異分數的測試片段,但執行時間顯著減少。
結論
在本文中,我們提出了一種新的方法 DS3,将具有多個測試場景的複雜系統測試用例分解為獨立的切片測試用例,每個測試用例運行一個測試場景。DS3 利用了在過去的回歸測試會話中收集的靜态切片和執行日志。其主要思想是使用包含關于 SUT 的運行時信息的日志來識别由于訪問和使用全局資源而導緻的測試語句之間的依賴關系;這些依賴關系用于細化由靜态切片生成的切片測試用例,而靜态切片往往會忽略這些依賴關系。在一個專有系統和一個開源系統上進行的評估結果表明,基于日志的切片細化确實有效地避免了生成的切片測試用例中由于缺少依賴而導緻的編譯或運行時錯誤。此外,生成的測試用例切片平均比原始系統測試用例快 3.56 倍,在故障檢測能力方面沒有顯著損失。
作為未來工作的一部分,我們計劃評估使用 DS3 對回歸測試活動的成本效益的影響,比如測試用例的優先級。我們還計劃擴展 DS3 以支持不同的編程語言,并在其他基準上對其進行評估。由于基于日志的切片的思想不僅适用于測試用例,而且也适用于一般的程序源代碼,我們将進一步研究回歸測試之外可能的應用程序。
緻謝
該工作已獲得盧森堡國家研究基金(FNR) No C-PPP17/IS/11602677 和加拿大 NSERC Discovery 和 CRC 項目的資助。
本文由南京大學軟件學院 2021 級碩士曹智豪轉述翻譯。
,