文章目錄
- 1 軟件單元驗證用例導出方法
- 2 測試用例完整性度量標準
- 3 驗證環境要求
- 4 軟件單元驗證的工作產品
1 軟件單元驗證用例導出方法
為確保軟件單元測試的測試案例規范符合9.4.2要求,應通過表8所列方法開發測試用例。
表8 軟件單元測試用例的得出方法:
備注:
a 等價類可以根據輸入和輸出的劃分來確定,這樣就可以為每個類選擇一個有代表性的測試值。
b 該方法用于接口、接近邊界的值、與邊界交叉的值及超出范圍的值。
c 錯誤猜測測試可以根據通過“經驗教訓”過程和專家判斷收集的數據進行。
-
1. 需求分析
-
專業解釋:
這是軟件單元測試用例生成的根本來源和起點。它系統地審查分配給軟件單元的功能性安全需求和非功能性需求(例如性能、資源約束)。測試用例需要明確覆蓋需求中規定的每個功能、輸入、輸出、前提條件、后置條件以及需求之間的邏輯關系(如順序、并發、互斥)。目的是確保需求文檔中定義的每一個預期行為都有對應的測試進行驗證,達成需求的“完全覆蓋”。 -
通俗解釋:
就像照著說明書來檢查一樣。工程師仔細閱讀軟件單元“應該做什么”的描述(這份說明書叫需求),然后根據里面的每一條描述,一條一條地設計測試方法,看看軟件在實際運行中是不是真的按照說明書說的那樣做了。說明書里提到的東西,一個都不能漏掉測試。 -
汽車行業實施示例:
-
需求: “當車速信號超過 180 km/h 時,單元 X 應當向控制單元 Y 發送‘超速警告’信號。”
-
測試用例設計:
- 準備一個模擬車速為 179 km/h 的信號作為輸入給單元 X。預期:單元 X 不發送‘超速警告’信號。
- 準備一個模擬車速為 180 km/h 的信號作為輸入給單元 X。預期:單元 X 發送‘超速警告’信號給單元 Y。
- 準備一個模擬車速為 181 km/h 的信號作為輸入給單元 X。預期:單元 X 發送‘超速警告’信號給單元 Y。
-
說明: 這里直接根據需求描述的觸發條件和預期動作來設計測試,確保軟件在觸發點前后都正確響應。
-
-
2. 等價類劃分與等價類分析
-
專業解釋:
這是一種基于輸入域分區的測試技術。它將所有可能的輸入數據劃分為若干“等價類”,在同一個等價類中的數據元素,預期軟件的行為是相同的(等價)。核心思想是:測試一個等價類的代表值就足以推斷該類中所有值的測試結果,從而顯著減少冗余測試用例的數量。等價類又分為有效等價類和無效等價類。有效等價類包含符合需求規定的合法輸入;無效等價類包含不符合規范、非法或不正確的輸入(如數據類型不符、超出范圍、空指針等)。測試用例需要覆蓋每個有效和無效等價類。 -
通俗解釋:
把軟件可能收到的各種輸入,分成幾個“小組”。同一小組里的數據,軟件處理的方式應該是一模一樣的。這樣就不用把小組里所有數據都測一遍,只要挑出小組里的“代表”,比如一個或幾個典型例子來測試就夠了。同時,不僅要測正常該輸入的“好數據”(有效小組),還要故意輸入一些“壞數據”(無效小組),比如錯的格式、超大的數、負數、空格等等,看軟件能不能識別錯誤并且正確處理(比如報錯、拒絕執行)。 -
汽車行業實施示例:
-
軟件單元功能: 計算發動機建議的換擋轉速 (基于當前發動機轉速 R 和節氣門開度百分比 P)。需求規定 R 有效范圍為 [800 rpm, 7000 rpm],P 有效范圍為 [0%, 100%]。
-
等價類劃分:
- 有效等價類 (V): R = [800, 7000], P = [0, 100]
- 無效等價類 (I): R 7000, P 100
-
分析: 有效等價類內部行為理論上應該是連續的,選擇內部一些點(如 R=1000, P=10%; R=4000, P=50%; R=6800, P=90%)進行測試就夠了。而無效等價類需要單獨測試:
- 測試 R=799 rpm (任何 P, 如 50%):預期:單元檢測到錯誤,輸出錯誤代碼或默認安全值。
- 測試 R=7001 rpm (任何 P, 如 50%):同上。
- 測試 P=-1% (任何 R, 如 3000 rpm):同上。
- 測試 P=101% (任何 R, 如 3000 rpm):同上。
-
說明: 避免了測試每個轉速和每個開度組合(那將是天文數字),用等價類大大提高了效率。
-
-
3. 邊界值分析
-
專業解釋:
這是等價類劃分技術的一種補充和強化策略,特別關注輸入域邊界附近的取值。經驗表明,軟件在邊界值點或其鄰近點(剛好在邊界內、剛好在邊界上、剛好在邊界外)發生錯誤的概率最高。因此,該方法針對每一個輸入變量的有效范圍邊界(最大值、最小值、特殊閾值)及其緊鄰的外部和內部值設計測試用例。它通常在等價類劃分的基礎上進行,為每個邊界點生成測試點(最小值、最小值+1、最大值-1、最大值等)。 -
通俗解釋:
重點檢查軟件在“邊界線”上表現怎么樣。比如軟件能處理的最大速度、最小電壓、臨界溫度等。測試時會特意輸入 剛好在邊界線上(如最大值)、比邊界大一點點、比邊界小一點點的數據,看看軟件會不會在極限情況下出錯、崩潰或者做出危險動作。例如,輸入是 0 到 100,那就特意測試 -1, 0, 1, 99, 100, 101 這些關鍵點。 -
汽車行業實施示例:
-
軟件單元功能: 根據電池電壓 (V) 判斷車輛啟動狀態。需求規定:V 16.5V 判為“電壓過高警告”。
-
邊界值分析:
- 低邊界: 測試 V = 8.9V (剛好低于9.0):預期:輸出“電池過低無法啟動”。
- 低邊界附近: 測試 V = 8.99V(或根據需要選擇一個略小于9.0的值)。
- 低邊界值: 測試 V = 9.0V:預期:輸出“準備就緒可啟動”。
- 低邊界內: 測試 V = 9.1V:預期:輸出“準備就緒可啟動”。
- 高邊界值: 測試 V = 16.5V:預期:輸出“準備就緒可啟動”。
- 高邊界附近: 測試 V = 16.49V(或根據需要選擇一個略小于16.5的值)。
- 高邊界: 測試 V = 16.5V + ε (例如 16.51V):預期:輸出“電壓過高警告”。
- 高邊界外: 測試 V = 17.0V:預期:輸出“電壓過高警告”。
-
說明: 嚴格測試 9.0V 和 16.5V 這兩個關鍵閾值及其緊鄰上下區域,確保邊界判斷邏輯絕對正確,避免臨界點附近誤判導致車輛啟動失敗或電氣系統過壓損壞。
-
-
4. 基于知識或經驗的錯誤猜測
-
專業解釋:
這是一種依賴于測試人員(往往是經驗豐富的工程師或軟件安全專家)的領域知識、以往故障模式數據庫積累和問題診斷直覺的啟發式方法。測試人員基于對特定技術(如指針運算、浮點精度、線程同步、資源管理)、平臺特性、歷史 Bug、常見軟件缺陷模式、標準或行業最佳實踐違背點的理解,推測軟件單元在哪些地方可能容易出現錯誤或存在潛在安全漏洞。然后,針對這些“容易出錯點”設計和執行特定的、可能不會被前述結構化方法輕易覆蓋到的測試用例。這是對結構化方法(需求分析、等價類、邊界值)的重要補充。 -
通俗解釋:
有點像一個經驗豐富的“老法師”來給軟件挑毛病。工程師們憑借自己多年的工作經驗和對汽車軟件特性的熟悉程度,特別是以前項目中踩過的坑、修過的 Bug,加上對軟件常見的“壞習慣”(比如資源泄漏、數值溢出、并發沖突、邊界沒處理好)的了解,主動去猜想“這個軟件在什么意想不到的情況下可能出錯?”。然后根據這些猜想設計一些“刁鉆”的測試案例,甚至模擬一些極端或不尋常的場景(比如突然斷電、傳感器信號突然消失、被輸入亂七八糟的數據)來進行攻擊測試。 -
汽車行業實施示例:
-
常見錯誤/風險點:
- 指針和內存: 對指針進行越界訪問后不檢查有效性。測試用例:傳遞一個 NULL 指針或已釋放內存的地址給單元,看是否會導致崩潰或產生不可預測行為。模擬內存分配失敗的情況。
- 數值處理: 變量范圍不夠大導致溢出。測試用例:輸入一個極端大的發動機扭矩值或積分值,看是否會溢出導致控制失效。
- 并發和時序: 多個任務同時訪問共享資源(如全局變量)可能引起的競爭條件。測試用例:設計測試場景讓單元在極高調用頻率下執行,或者同時觸發多個中斷訪問同一數據。
- 硬件/環境故障模擬: 傳感器瞬間失效或信號跳變。測試用例:讓輪速傳感器信號突然從 100km/h 跳變為 0km/h(模擬輪速傳感器失效),看電子穩定控制系統軟件是否會導致誤判、過度修正或宕機。測試 CAN 總線通信中斷時單元的降級模式是否符合安全要求。
- 極端操作條件: 車輛在極寒(-40°C)或極熱(85°C)環境下啟動時,軟件初始化是否能正確處理時間延遲和資源加載。
- 特定算法陷阱: 如除法操作可能除以零。測試用例:輸入可能導致除數為零的計算參數。
- 非預期輸入序列: 如要求必須先調用 FunctionA 再調用 FunctionB,但故意先調用 FunctionB。或者在電池管理單元測試中,連續發送完全沖突的充電和放電指令。
- 安全機制測試: 故意觸發軟件單元內部設計的安全機制(如看門狗喂狗邏輯不正確、程序流監控報錯等),看機制是否有效觸發并執行預期安全動作(如進入安全狀態)。
-
整合與應用:
在實際項目中,這四種方法必須結合使用,缺一不可:
- 需求分析是根基: 確保測試覆蓋了所有指定的功能。
- 等價類和邊界值是結構化的“主力軍”: 高效、系統性地覆蓋輸入域和關鍵邊界點。
- 錯誤猜測是關鍵的“補充火力”: 探測那些結構化的常規測試難以覆蓋的、意想不到的角落,特別是由于實現缺陷、環境異常或攻擊性輸入導致的問題,對功能安全尤其重要。
在汽車行業,嚴格的軟件單元測試是確保車輛電子電氣系統功能安全(FuSa)的基石。通過系統性地應用這些方法導出測試用例并嚴格執行,可以顯著降低軟件單元中的系統性故障風險,滿足 ASIL 等級(A、B、C、D)的安全性要求。
2 測試用例完整性度量標準
為了評估測試用例的完整性并證明沒有非預期的功能,應確定在軟件單元層面的要求覆蓋率,同時應按照表9列出的度量對結構覆蓋率進行測定。如果認為已實現的結構覆蓋率不充分,應定義額外的測試用例或提供接受理由。
表9 軟件單元層面的結構覆蓋率度量:
-
注1:沒有理論基礎的結構覆蓋率的目標值或低目標值都被認為是不充分的。
示例1:結構覆蓋率分析可以顯示基于需求的測試用例的不足、要求的缺陷、無作用碼、無效代碼或非預期的功能。
示例2:基于可接受的無作用碼(例如:用于調試的代碼)或不同軟件配置的代碼區段可以給出接受所達到的覆蓋率水平的理由;或可以使用補充方法(例如:檢查)驗證未被覆蓋的代碼。
示例3:理論基礎可以建立在當前最佳狀態基礎上。 -
注2:結構覆蓋率可以通過使用適當的軟件工具來確定。
-
注3:在基于模型開發的情況下,結構覆蓋率分析可以利用相似的模型結構覆蓋率度量在模型層面進行。
示例4:如果在模型級別執行的結構覆蓋率被證明是等價的,那么對它的分析可以替換源代碼覆蓋率度量,且其理論基礎基于這樣一個證據:覆蓋率代表代碼級別。 -
注4:如果使用測量代碼來確定結構覆蓋率的程度,那么就有必要提供證據證明該測量對測試結果沒有影響。這可以通過使用非測量代碼重復進行具有代表性的測試案例來實現。
-
1. 語句覆蓋率 (Statement Coverage, SC)
- 定義: 度量單元驗證測試用例集合執行了軟件單元中所有可執行語句的程度。
可執行語句
通常指賦值語句、函數調用、控制流語句(如if
,for
,while
,switch
等)本身(但不包括其內部的條件)。- 非執行語句(如注釋、聲明、空行等)不計入。
- 作用:
- 最基礎的覆蓋指標,用于發現“死代碼” (Dead Code) - 那些在正常或錯誤條件下都永遠不會執行的語句。
- 識別部分未測試的代碼路徑。
- 滿足 ASIL A/B 級別的基本要求或作為更高級別覆蓋的基礎。
- 公式:
SC = (已執行的可執行語句數 / 總可執行語句數) * 100%
- 實施過程:
- 編譯設置: 啟用編譯器的代碼插樁功能(通常生成帶插樁點的可執行文件)。
- 執行測試: 運行所有單元測試用例。
- 覆蓋分析: 收集插樁點執行數據(哪些語句被執行),由覆蓋率工具(如 VectorCAST, LDRA Testbed, Tessy, CTC++, Gcov, BullseyeCoverage)分析并計算 SC。
- 報告與評估: 查看覆蓋率報告,找出未覆蓋的語句,分析原因(邏輯錯誤?測試用例缺失?異常路徑未覆蓋?)。
- 提升覆蓋率: 針對未覆蓋語句設計新的或修改現有測試用例。目標通常是 100% SC (對于所有 ASIL 級別)。
- 局限性:
- 無法保證控制流決策的邏輯被充分測試(即使語句都執行了,決策的真/假分支可能沒覆蓋全)。
- 無法保證所有條件組合或獨立影響被測試到。
- 實例:
考慮以下函數片段:
int calc(int a, int b, int op) {int result = 0; // Executable stmt 1if (op == 1) { // Executable stmt 2 (The 'if' itself)result = a + b; // Executable stmt 3} else {result = a - b; // Executable stmt 4}return result; // Executable stmt 5 }
- 總共有 5 條可執行語句(注釋行不計)。
- 測試用例
calc(2, 3, 1)
:- 執行
result = 0;
->if (op == 1)
->result = a + b;
->return result;
- 覆蓋了 stmt 1, 2, 3, 5。
- 執行
- 未覆蓋 stmt 4 (
result = a - b;
)。 - SC = (4 / 5) * 100% = 80%。
- 為了達到 100% SC,需要增加一個執行
else
分支的測試用例,如calc(5, 2, 2)
(假設op !=1
走else
)。
-
2. 分支/判定覆蓋率 (Branch Coverage, Decision Coverage, DC)
- 定義: 度量單元測試用例集合執行了軟件單元中所有控制流分支的程度。每個控制流點(
if
,switch
,while
,for
,?:
,&&
,||
)的真值分支 (true
) 和假值分支 (false
) 都應被執行。 - 也被稱為邊覆蓋 (Edge Coverage),因為它關注控制流圖 (CFG) 中邊的覆蓋。
- 不同于條件覆蓋率 (Condition Coverage),后者關注布爾表達式中每個原子條件的真假值,但不一定組合成所有可能的判定結果。
- 作用:
- 確保決策點所有的可能出口路徑都被測試到。 防止遺漏關鍵的
true
或false
邏輯路徑。 - 滿足 ASIL B 級別的要求,也是 ASIL C/D 級別 MC/DC 的先決條件。
- 公式:
DC = (已執行的分支數 / 總分支數) * 100%
- 注意:對于簡單的
if-else
,通常算作一個判定點,有 2 個分支(true
和false
)。對于if
沒有else
,沒有顯式的else
分支也被視為一條隱式的空分支(從判斷點直接流出),也需要覆蓋。 - 實施過程:
- 與 SC 實施過程類似(步驟 1-3),覆蓋率工具同樣會記錄每個控制流點的真假分支是否被執行。
- 分析報告中的
DC
(或類似指標,有時工具可能稱其為 “Condition Coverge” 或 “Branch Condition Coverage” - 注意區分術語)。 - 識別并覆蓋未執行的分支。目標通常是 100% DC。
- 局限性:
- 對于一個由多個條件組成的布爾表達式(例如
if (A && B)
),100% DC 可以通過只測試兩種路徑實現:A=true, B=true
(判定結果為true
,覆蓋true
分支)A=false
(B
的值無關,因為短路計算,判定結果為false
,覆蓋false
分支)
- 這種情況下,
A=true, B=false
導致判定結果為false
的路徑沒有被測試!DC 沒有揭示條件組合的問題,無法保證每個條件的獨立影響被測試。這就需要 MC/DC。 - 實例:
使用上面的calc
函數:
int calc(int a, int b, int op) {int result = 0;if (op == 1) { // 這是一個判定點result = a + b;} else { // 顯式的else分支result = a - b;}return result; }
- 這個
if-else
結構構成了一個判定點,有 2 個分支:true
分支(op == 1
為真,執行加法)。false
分支(op == 1
為假,執行減法)。
- 測試用例
calc(2, 3, 1)
:op == 1
為真 -> 覆蓋true
分支。
- 測試用例
calc(5, 2, 2)
:op == 1
為假 -> 覆蓋false
分支。
- 兩個分支均被覆蓋 -> DC = 100%。
- 如果只有
calc(2, 3, 1)
,只覆蓋了true
分支,DC = 50%。
- 定義: 度量單元測試用例集合執行了軟件單元中所有控制流分支的程度。每個控制流點(
-
3. 修正條件/判定覆蓋 (Modified Condition/Decision Coverage, MC/DC)
- 定義: 這是 ISO 26262 對 ASIL C/D 級別強制執行的要求。它比 DC 更嚴格。
- 目標: 保證在一個布爾判定中(由多個條件組成),每個條件的獨立影響于該判定的最終結果都能被演示。
- 核心要求:
- 判定覆蓋 (Decision Coverage): 每個判定的所有可能結果必須至少被測試一次(
true
和false
)。 - 條件覆蓋 (Condition Coverage): 判定中每個條件的所有可能值(
true
和false
)必須至少被測試一次。 - 獨立影響 (Independence): 對于每個條件
C
, 必須存在兩對測試用例:- 兩對用例中,除了條件
C
的值不同外,其他所有條件的值完全相同。 - 條件
C
值的改變,獨立地導致了整個判定結果的改變(即一對用例判定結果不同)。
- 兩對用例中,除了條件
- 判定覆蓋 (Decision Coverage): 每個判定的所有可能結果必須至少被測試一次(
- 滿足獨立影響要求即可自動滿足條件覆蓋和判定覆蓋。
- 優化:只需
n+1
個測試用例(n 是判定中條件的個數)就能滿足 MC/DC(優于條件組合覆蓋2^n
)。 - 作用:
- 最有效地揭示由多個條件組合的邏輯錯誤、缺失需求和規格誤解。
- 確保邏輯表達式中的每個條件都能獨立控制輸出(在特定輸入組合下)。
- 對安全關鍵軟件提供高水平的可靠性保證。
- 實施過程:
- 識別目標判定: 定位那些由多個條件組成的復雜布爾表達式(通常出現在
if
,while
,switch
條件或布爾變量賦值中)。 - 分析條件: 確定判定表達式中的所有原子布爾條件。
- 設計滿足 MC/DC 的測試用例: 對每個條件
C_i
,找出或設計滿足其獨立影響要求的用例對。關注哪些條件可以固定以觀察C_i
的變化是否獨立影響結果。 - 執行測試用例: 運行這些精心設計的測試用例。
- 覆蓋分析: 使用支持 MC/DC 分析的覆蓋率工具(如 VectorCAST, LDRA Testbed, Tessy, CTC++, Cantata)收集和分析數據。工具會報告每個條件的獨立影響是否已被證實(
MC/DC True
)以及整體 MC/DC 百分比。 - 報告與評估: 識別未被證明獨立影響的條件。目標必須是 100% MC/DC。
- 提升覆蓋率: 為每個未達標的條件設計或補充缺失的用例對。
- 局限性: 主要在于實施的復雜性、分析和設計測試用例所需的時間/精力,尤其對于龐大或嵌套復雜的判定。
總結與關鍵實施建議:
- 工具依賴性強: 可靠的結構覆蓋分析高度依賴專業的覆蓋率工具。需要支持 SC、DC 和 MC/DC,并能與目標編譯器和嵌入式環境(或模擬器/仿真器)協同工作。
- 環境模擬至關重要: 嵌入式環境的限制(資源、硬件依賴)常需使用軟件在環(SIL)、處理器在環(PIL)測試或功能強大的模擬環境。
- 100% 目標: ISO 26262 期望(對相關安全部分)達到盡可能高的覆蓋率(接近100%),尤其是 SC/DC/MC/DC。所有未覆蓋點都必須進行合理性論證(Justification)(如證明該代碼不可能執行,或與安全無關)。
- 測試用例設計優先: 覆蓋率是測試充分性的證據,設計出能夠暴露問題的好的測試用例才是核心。覆蓋率是衡量測試完整性的度量工具。
- 關注異常和邊界: 單元測試必須覆蓋錯誤輸入、邊界值條件以及中斷/異常處理路徑,這些地方往往是缺陷高發區。
- 集成到開發流程: 將覆蓋率分析集成到持續集成(CI)流水線中,使其成為自動化構建和測試的一部分。
- 評審: 覆蓋率結果和未覆蓋點的合理性論證需要經過評審。
3 驗證環境要求
對于軟件單元驗證的測試環境,應該盡可能地接近目標環境。如果軟件單元測試不是在目標環境下執行,應分析源代碼和目標代碼的差異及測試環境和目標環境之間的差異,以便在后續測試階段的目標環境中,定義額外的測試。
注1:測試環境和目標環境之間的差異,可出現在源代碼或目標代碼中,例如,由于不同處理器的數據字和地址字的不同位寬引起的差異。
注2:根據測試范圍,使用適當的測試環境(例如目標處理器、處理器仿真器或開發系統)執行軟件單元測試。
注3:軟件單元測試可以在不同的環境中執行,例如:
- 模型在環測試;
- 軟件在環測試;
- 處理器在環測試;
- 硬件在環測試。
(后續介紹以上四類測試)
注4:對基于模型的開發,在模型層面執行軟件單元測試,隨后,在模型和目標代碼之間進行背靠背的比較測試。背靠背的比較測試用于確保關于測試對象的模型表現等同于自動生成的代碼。
4 軟件單元驗證的工作產品
軟件單元驗證報告(Software Unit Verification Report): 匯總所有驗證活動(靜態分析、動態測試、評審等)的結果、覆蓋度指標、識別的缺陷及其狀態、以及是否符合入口/出口準則的結論。詳細記錄每個測試用例的執行結果、日志、通過的證明或缺陷報告。
(測試)覆蓋度報告((Test) Coverage Report): 展示測試活動對代碼(如語句覆蓋、分支覆蓋、MC/DC覆蓋)或需求(需求覆蓋)的覆蓋程度,證明驗證的充分性(尤其針對ASIL D的高要求)。
軟件單元測試規范(Software Unit Test Specification):內容:由需求輸入衍生而來。詳細描述針對每個軟件單元的具體測試用例、測試輸入數據、預期輸出結果、測試環境設置、以及執行的先決條件。作用:核心執行依據。 直接指導動態測試(如單元測試)的執行。
📌 應用提示:
- ASIL等級決定嚴格度:ASIL等級越高(如D級),對測試覆蓋度(如MC/DC)和文檔完備性要求越嚴格
- 工具鏈需認證:若使用自動化測試/分析工具,需符合ISO26262-8的工具鑒定(Tool Qualification)要求
- 版本一致性:所有輸入文檔必須保持版本同步,避免因文檔迭代導致驗證偏差