聯系電話:
+886 2 77182788
創提部落格
希望我們能與您分享和探討成長中的點點滴滴
程式碼覆蓋率:為什麼達到100%仍然不夠?
創提科技
2026/09/28
分享到
轉載自vector
程式碼覆蓋率是評估汽車軟體在開發過程中是否符合相關標準要求的一個常用指標。然而,不應將其視為唯一目標,因為即使覆蓋率達到100%,也無法保證驗證結果的可靠性或充分性。
程式碼覆蓋率是當今任何開發流程中不可或缺的一部分,並已成為軟體發展中最受歡迎的指標之一,因為它既易於測量又易於理解。然而,100%的程式碼覆蓋率並不意味著軟體已經得到充分驗證。看到100%的程式碼覆蓋率會給人一種完整的感覺,畢竟每一行程式碼都已執行。然而,這種假設引發了幾個問題。
首先,需要明確用於測量程式碼覆蓋率的方法。不同的方法可能會導致不同的結果。此外,還必須明確覆蓋率是基於什麼物件進行測量的。要回答這個問題,需要進一步探討。本文探討了程式碼層面的覆蓋率要求,並說明了覆蓋率可以且應該用於哪些方面。此外,本文還舉了一個僅靠程式碼覆蓋率就可能足夠的案例。本文不會解釋程式碼覆蓋率的各種類型。
如前所述,程式碼覆蓋率測量是許多重要軟體發展標準中的組成部分。汽車行業也不例外。如果你仔細查看“常見標準”,就會發現不同標準對程式碼覆蓋率的要求各不相同。
汽車SPICE(ASPICE)是許多開發專案的基礎。例如,在3.1版本中,SWE.4 軟體單元驗證仍然提到覆蓋率目標值可以用作單元驗證的標準。到了2023年底發佈的4.0版本,只提到了驗證覆蓋率。該標準目前並未明確規定具體應如何實施。
由於網路安全如今與所有使用軟體的行業都息息相關,因此針對汽車行業的 ISO 21434 標準如今也幾乎被廣泛採用。但在軟體發展安全的實際實施方面,該標準給出的具體規定非常少,許多地方以建議為主。其中包括一條建議:如果選擇通過測試進行驗證,則應使用覆蓋率指標來判斷測試活動的適當性。此外還有一條注釋指出,單純的語句覆蓋率可能不足以滿足網路安全的要求。
道路車輛功能安全標準專門在第6部分(ISO 26262-6:2018)中對軟體發展進行了論述。在關於軟體單元驗證的章節中,表9明確列出了應根據關鍵性級別記錄哪些覆蓋率指標。ISO 26262 還定義了進行覆蓋率測量的目標。包含表 9 的要求 9.4.4 規定,應進行覆蓋率測量以評估驗證的完整性,並提供客觀證據證明單元測試目標已實現。
而第 9.1 章對單元測試的目標定義如下:
● 證明已實現的軟體單元符合設計並滿足指定的軟體需求。
● 提供充分證據,證明其中既不包含非預期功能,也不包含非預期屬性。
或者用兩個詞概括就是:正確性和完整性。
此前已指出,程式碼覆蓋率的概念與完備性概念密切相關。然而,程式碼覆蓋率無法對程式碼的正確性——即程式碼是否滿足其被賦予的需求——做出任何判斷。在這方面,通常會使用直接基於需求的測試用例。無論該需求來自需求管理工具、用戶故事還是其他形式的預期,都無關緊要。一次成功的測試可以提供有關某項功能是否已實現的資訊。通過用測試覆蓋所有需求,可以對程式碼的正確性做出判斷。這裡同樣涉及“覆蓋率”的概念,即測試覆蓋率(即測試用例的覆蓋率)。此時,程式碼覆蓋率使得評估程式碼的完整性成為可能,前提是在執行所有基於需求測試的過程中確定了適當的覆蓋率。原則如下:如果通過完整的測試覆蓋率證明了正確性,那麼結合完整的程式碼覆蓋,可以進一步評估測試活動在程式碼結構層面的完備性。測試覆蓋率與程式碼覆蓋率相輔相成,因此具有互補性(見圖1)。

圖1 測試覆蓋率和程式碼覆蓋率,結構覆蓋分析的結果,作為互補目標
為了更好地理解如何從正確性陳述中推導出完備性,有必要將視野擴展到汽車行業特定標準的範圍之外。儘管 ISO 26262-6:2018 在 9.4.4 節的示例 2 中也列舉了覆蓋率缺失的各種原因,但在其他標準中可以找到描述更為詳盡的流程。航空電子領域的軟體發展標準 RTCA/DO-178C 詳細描述了覆蓋率測量結果應如何使用。首先,執行所有可用的測試並記錄所達到的覆蓋率。然後,對未被覆蓋的程式碼部分進行審查。
這可能有多種原因(圖2):
A. 需求不完整。
B. 需求尚未經過全面測試。
C. 該程式碼是根據編碼規範(防禦性編碼)而存在的,或者因其他合理原因無法訪問或無法獲取。
D. 該程式碼可有可無。

圖2 此過程中程式碼覆蓋率不足的可能原因
針對這些原因,每一種都有明確的應對措施。可能是增加需求(A)、增加更多測試(B)、記錄原因(C)或刪除多餘的程式碼(D)。這裡可以看出,這其實是一個反覆運算的過程,而不僅僅是一次性的分析。它也表明,程式碼覆蓋不僅包括測試執行時測得的覆蓋率,還包括理由說明和分析,特別是在情況C中,這通常成為“通過分析獲得的覆蓋(Coverage by Analysis, CBA)”。
如果在這個過程中實現了完整的程式碼覆蓋,可以得出以下結論:
● 相對於程式碼而言,需求是完備的。
● 測試已全面覆蓋這些需求(測試覆蓋率)。
● 對於測試無法觸及的每一段程式碼,都有合理的說明。
● 沒有多餘的程式碼。
前文的論述始終假設程式碼覆蓋率是基於需求驅動的測試來測量的。但這並非實現程式碼覆蓋率的唯一途徑。不過,由此得出的結論也會有所不同。例如,源程式碼覆蓋率可以通過靜態分析來測量。儘管人們常聲稱可以達到100%的覆蓋率,但這並非真正的程式碼覆蓋率,因為在分析過程中程式碼並未被執行。不過,這種方法也能涵蓋程式碼覆蓋率分析的某些方面,並揭示出無法執行和可省略的程式碼。但無法通過這種方式證明程式碼在指定需求方面的正確性。該評估基於源程式碼的結構,僅檢查語法正確性和邏輯結構。因此,“完整性”的論斷僅能指分析本身。而分析類型並不改變這一論斷,因為對程式碼的形式化分析同樣屬於靜態分析,且不會執行程式碼。即使是基於程式碼的測試——即基於程式碼結構而非需求進行的測試——也能實現完整的程式碼覆蓋率,儘管無法就此對正確性作出斷言。儘管如此,這些測試仍有其作用:
作為所謂的特徵化測試(characterization tests),它們可用於描述程式碼當前的功能。如果源程式碼通過這種方式實現了全面覆蓋,那麼對現有程式碼的修改就能更輕鬆、更高效地實施。一旦程式碼發生變更,這些測試就能顯示出程式碼行為在哪些地方發生了變化——無論是有意還是無意的。因此,在修訂或重構遺留程式碼時,會使用這些具有完全程式碼覆蓋率的測試。
如果“在運行過程中”測量程式碼覆蓋率,這對排查故障會大有説明。這種情況下,目標既不是正確性,也不是完整性。其目的是確定錯誤或崩潰發生的位置,例如。
唯一剩下的問題是,理想情況下應該基於什麼來測量程式碼覆蓋率。仔細分析後會發現,有多種可能性:基於原始源程式碼、翻譯單元、彙編程式碼、可執行目標程式碼或可執行檔。
1. 前置處理器將源程式碼轉換為所謂的翻譯單元。
2. 編譯器根據翻譯單元生成彙編程式碼。
3. 彙編器將彙編程式碼轉換為目的檔案。
4. 連結器將目的檔案合併為可執行檔。

圖3 編譯過程中的構建管道,以及人類和機器對其可讀性的評估
隨著每個階段的推進,關注點也在不斷轉變:
雖然源程式碼是為編譯而寫的,但它仍然是為人類可讀設計的。它包含注釋,允許簡化,宏還沒有展開,並且可能存在條件編譯指令。預處理會去掉編譯器不需要的內容,並進行必要的替換。結果仍然可以被人閱讀,但已經和原始源程式碼有明顯差別。隨著進一步的步驟,人類可讀性會下降,程式碼越來越被優化以便在目標系統上執行,直到最終被翻譯成機器碼。
ISO 26262 並未明確規定在構建流程的哪個階段應顯示程式碼覆蓋率(並達到目標值),但其相關要求傾向於在目標系統上執行測試。如果測試在主機上進行,則應單獨考慮與目標系統之間的差異。這最初並不影響已達到的程式碼覆蓋率顯示的位置。出於效率考慮,通常選擇易於人類閱讀的格式,主要是翻譯單元或源程式碼,因為這樣更容易據此得出結論並採取必要措施。這兩種格式各有優缺點。例如,翻譯單元僅顯示計畫進行進一步編譯的程式碼(圖 4)。

圖 4 在翻譯單元上顯示的“SourceFilePerspectiveDemo”函數的程式碼覆蓋率
然而,預處理後注釋會被移除,而根據配置通過條件編譯包含或排除的程式碼,也只會保留當前配置對應的部分。而這正是主機與目標系統之間可能出現差異的地方,因為通常必須針對主機上的編譯進行調整。因此,主機和目標的翻譯單元之間存在差異。即使對於不僅用於一個變體的源程式碼,原始源程式碼與翻譯單元之間也可能存在顯著差異(圖 5)。因此,建議在源程式碼上顯示程式碼覆蓋率,因為這也能顯示出當前編譯中未被包含的程式碼段。

圖5 “SourceFilePerspectiveDemo”函數在源程式碼上的程式碼覆蓋情況
程式碼覆蓋率是一個重要的指標,但應該正確使用。將程式碼覆蓋率作為孤立的目標並無太大意義,僅憑程式碼覆蓋率本身也不足以得出可靠結論。正如本文所述,它更適合作為補充性證據。如果明確了測量程式碼覆蓋率的目的並正確解讀結果,那麼程式碼覆蓋率就能夠成為一項有力且值得記錄的驗證證據。