測試是(shì)一(yī)個(gè)非常基礎的(de)λε≥♠概念,這(zhè)種基礎讓大(dà)家(jiā)可¥&©(kě)以随意在它前面添加各種定語。
盡管這(zhè)種添加的(d↑↔↓εe)背後多(duō)數(shù)是(shì)不(bù)同的(de)分(fēn)類維度,但©↕ ♠(dàn)讓測試本身(shēn)成為(wèi)了(le)繁雜(↑♣©zá)概念的(de)集合,這(zhè)也(yě)讓我們總有(yǒu)種無法把握的(de)煩躁感。
單元測試就(jiù)是(shì)這(z ≈hè)堆讓人(rén)煩躁的(de)繁雜(zá)概念之一(yī)。
1 3種軟件(jiàn)測試分(fēn)類及單元測試的(de)定義
如(rú)♥$↓前所述,軟件(jiàn)測試的(de)分(fēn)類維度非常多(duō),我們僅從(cóng)以λ♠™•下(xià)常見(jiàn)的(de)3種方式闡釋:
- 按是(shì)否執行(xíng)軟件(jφ¶™iàn)分(fēn)類:靜(jìng)态測試和(hé)動态測試,單元測試橫跨二者。
- 按是(shì)否關注內(nèi)部代碼分(fēn)類:α§白(bái)盒測試和(hé)黑(hēi)盒測試,單元測試屬于白(bá₽÷§<i)盒測試。
- 按汽車(chē)軟件(jiàn)集成層次分(fēn)類:從(cóng)單元測試到(dào)整♦♥'¶車(chē)驗收有(yǒu)各級測試(參考《汽車(chē)軟件(jiàn)集成的(de)¶σ 5個(gè)層次》),單元測試屬于最低(dī)一(yī)個(gè↔£¥→)層級。
當我δ 們去(qù)網上(shàng)搜索單元測試的(de)定¶&義時(shí),往往會(huì)看(kàn)到(dào)類似這(zλ®hè)樣的(de)說(shuō)法,“單元測試是(shì)指對(duì)軟件(jiàn)中的♣$∑(de)最小(xiǎo)可(kě)測單元進行(xíng)測試”。
但Ωγ≤'(dàn)這(zhè)個(gè)描述隻能(néng)是≠€'(shì)一(yī)個(gè)正确的(de)定義,仍然很(hěn)難把握。什(shéπ₽n)麽叫最小(xiǎo)可(kě)測單元?一(yī)個(gè↔♠λα)函數(shù)?一(yī)個(gè)類?一(yī)個(gè).c?還(hái)是(shì)↕↔一(yī)個(gè)功能(néng)模塊?
争論一(yī)直存在$§ ∑。
擱置争議(yì),我們隻看(↓©kàn)汽車(chē)行(xíng)業(yè)。按照(zhà↔♥δ↕o)慣例或标準,廣義上(shàng),可(kě)以把軟件(jiàn)集成測試以下(xià)所有(yǒu)測試都(dōu)看(kàn)作(zuò)是( ♦↕≥shì)單元測試。
2 單元測試的(de)4種類型
進一(yī)步地(dì),在汽車(chē)軟 ♣件(jiàn)領域,我們可(kě)以将單元測試細分(fēn)為(wèi)代碼評審、β≤ 靜(jìng)态分(fēn)析、單元(代碼功能(néng))≈↑測試和(hé)單元(代碼覆蓋度)測試。
前兩種屬于靜(jìng)态測試 £♥,後兩種屬于動态測試。
 δ♥;2.1 代碼評審
根據形式或正式程度上λ₹(shàng)的(de)差異,代碼評審會(huì)分(fēn)成很(hěn)多(duō)名目,比€¥如(rú):
- €♣×;走查(Walk Through)
- 同行(xíng)評審(Peer Review)
&n ♦λ±bsp;- 代碼評審(Code Revew)
- 結對(du♣•$ì)編程(Pair Programming)
- 代碼審查(Code Inspection)
但(dàn)簡單來(÷€♠lái)說(shuō),代碼評審就(jiù)是(shì)人(rén)♣↑©看(kàn),一(yī)個(gè)或一(yī)組人(rén)面'★對(duì)可(kě)閱讀(dú)的(de)源代碼(有(yǒu)時(✘→shí)也(yě)需要(yào)結合需求或軟件(jiàn)文(wén)檔),進行(xíng)随意₹≤的(de)或正式會(huì)議(yì)下(xi₩♣✔♠à)的(de)檢查。
可(kě)能(néng)會(huì)←π™$識别出如(rú)下(xià)的(de)一(yī§₩)些(xiē)問(wèn)題:
- 無注釋的(de)代碼
- 不(bù)可(♠®kě)達的(de)條件(jiàn)路(lù)徑
&nb✘ε↕₩sp;- 太複雜(zá)的(de)循環嵌套
- 無返回值的 ✘♥(de)分(fēn)支
- 未初始化(hu♦εà)的(de)變量
- 空(kōng)指針的(de)引用(yò₩&γng)
- 不(bù)規範的₹♥(de)命名規則
- ......
理(lǐ)論上γ®×(shàng),對(duì)于手寫代碼的(de)合理(lǐ)性與正确性,他(tā)人(rén ∞)及更有(yǒu)經驗的(de)他(tā)人(rén)去(qù)檢查一(yī)✘♥遍,有(yǒu)一(yī)定的(de)意義,甚至某些(xiē)案€₩例下(xià),會(huì)勝過後期測試。
比如(rú),開(kāi)發調用(yòng)了(leε÷)名稱相(xiàng)似的(de)變量,這(zhè)種錯(cuò)誤可(✘<≠kě)能(néng)在流到(dào)很(hěn)後期才會(hu♥€ì)被探測到(dào)。
實際上(shàng),代碼評審也(yě)同其他(tā)評審類似,都(dōu)是(shì)׶®無奈為(wèi)之而又(yòu)常常流于形式的(de)手段。
解決這(zhè)類問(wèn)題的(de)方 ≈法不(bù)外(wài)乎3個(gè):
- 用(yòng)更負責且₹★♦₽有(yǒu)經驗的(de)人(rén)
- 提升形式的(de)強制(zhì)性
↕∑- 積累充足的(de)Checklist
其中,在下(xià)一(yī)節靜∞≥₩(jìng)态分(fēn)析工(gōng)具使用(yòng)後,人(rén)的(de)經驗就(jiù)成為(wèi)了(le)代碼評審存♥α✘在的(de)最大(dà)意義。
總之,代碼評審不(bù)算(suàn)是♥¶€(shì)典型的(de)測試,但(dàn)作(zuò)為(wèi)編碼後的(de)第一(yī)∞↕±©道(dào)屏障,仍然有(yǒu)必要(yào₩λ©)存在。
2.←∏•2 靜(jìng)态分(fēn)析
相(xiàng)較于人(rén)工(gōng♣÷φσ)代碼評審的(de)低(dī)效,靜(jìng)态分(fēn)析是(shì♥ &≥)依賴于諸如(rú)Parasoft、Polyspace、Coverity等工(gōng)具δβ$☆的(de)自(zì)動化(huà)分(fēn)析。
因為(wèi)不(bù¶ε∞∏)需要(yào)執行(xíng)軟件(jiàn),所以靜(jì↑•ng)态分(fēn)析仍然不(bù)需要(yàoγ₹≤)二進制(zhì)代碼或可(kě)執行(xíng)程序。
靜(jìng)态分(✔δ©£fēn)析工(gōng)具通(tōng)常主要(yào)支持以下(xiàλ∞)兩種分(fēn)析類型:
- ✔♣;語法分(fēn)析:主要(yào)檢查是(shì)否符合編程語言的(de)語法規則,如(rú)MISRA ♣λαC。
- ✘®;代碼路(lù)徑分(fēn)析:主要(yào)包括控制(zhì)流分(fēn)析(如(rú)語句條件(j≤$ε€iàn)分(fēn)支、循環叠代次數(shù))、數(shù)據流分(fē•£n)析(如(rú)變量值的(de)傳遞)、♦♥代碼複雜(zá)性(如(rú)圈複雜(z☆®á)度、路(lù)徑長(cháng)度)、依賴關系(如(rú)函數(shù)之間(j÷ iān)的(de)調用(yòng)、模塊之間(jiān)的(de)依賴)等。
↕± 當對(duì)部分(fēn)或全部代碼進行(xíng)靜(jìng)态掃描 δ後,會(huì)得(de)到(dào)基于內δ♦(nèi)置規則集的(de)判定結果,一(yī)∞¥般會(huì)包含分(fēn)等級的(de)規則違反情況。
$↔π如(rú)MISRA C: 2012分(fēn)為(wèi)強制(zhì)(Mandatory)、必要(yào)(Required)和(hé)建議(yì)(Advisory)。
通(tōng)常,強制(zhì)項Ω≠γ必修,必要(yào)項需要(yào)進行(xíng)評審。但(dàn)有(•±βyǒu)時(shí)候,涉及到(dào)第三方标≥★δ 準庫時(shí),就(jiù)無法按照(zhΩ ✔Ωào)這(zhè)個(gè)規則執行(xíngβ★₩)了(le),具體(tǐ)還(hái)是(shì)要(yào)©₽✘看(kàn)産品類型(如(rú)是(shì)否涉及φ✘≈信息安全)和(hé)公司要(yào)求。
此外(wài),由于編譯器(qì)基本也(yě)都(dōu)具備類¥似的(de)代碼檢查作(zuò)用(yòng),靜(jìng)态分(f✘♥ēn)析工(gōng)具也(yě)可(k→☆ě)以理(lǐ)解為(wèi)編譯器(qì)的(δ £εde)擴展。
&nbs<♠↑γp;因此,我們也(yě)會(huì)把編譯器(qì)警告或錯(cuò)誤作(zuò)為(wèi×★¥)要(yào)處理(lǐ)的(de)條目。
&nbs↕↔p;2.3 單元(代碼功能(néng))測試
 ≈♦™₽;這(zhè)部分(fēn)測試的(de)源頭是(shì)軟件(jiδ×αàn)詳細設計(jì),測試重點從(cóng)代碼寫得(de)漂不(bù)β∏÷漂亮(liàng)轉移到(dào)代碼寫得(de) α有(yǒu)沒有(yǒu)用(yòng),也(yě)就(jiù)是(shì)是(shì)不(bù)是×"↕×(shì)符合了(le)設計(jì)。
汽車(chē)軟件(jiàn>'÷¶)用(yòng)例的(de)設計(jì),一(yī)般有(yǒu)如(rú↕α)下(xià)兩種密切相(xiàng)關的(de)方法:
2.3.1 等價 ¶類劃分(fēn)法
等價類劃分(fēn)是(shσ✘ì)将軟件(jiàn)單元的(de)輸入數(shù)據劃分(fēn)為(wèi)等價™≤±'數(shù)據(即可(kě)以導緻相(xiàng)同的(de)輸出)的(de)&"♠分(fēn)區(qū),而後用(yòng)測試用(yòng)例去( λ☆₽qù)至少(shǎo)覆蓋每個(gè)分(fēn)區(qū)一(yī)次。
&n§≤λbsp;其背後的(de)訴求是(shì),通(tōng)過劃分(fēn)輸入數(shù)據的(de∑$±Ω)類别來(lái)限定測試用(yòng)例的(de)數(shù)量。舉一(yī)個(gè)例子(zǐ)。
一(yī)個(gè♦↕≥)函數(shù)輸入的(de)範圍是(shì)1~100,如(rú)果要(yào)窮舉式測試,我們需要(yào)為(wèi)輸入參數(shù)編寫100個(gè)>↑ε×測試用(yòng)例。
而使用(yòng)等價類劃分(fēn)法的 ≈©(de)話(huà),測試用(yòng)例就(jiγ ♠ù)可(kě)以分(fēn)為(wèi)三類:
≤¥•¶ - 有(yǒu)效(1~100)
- 以下(xià)無βλ 效(例如(rú)0)
- 以上(shàng)無效(>100)✔•≠§
于是(shì),用(yòng)例也(yě§→Ω )就(jiù)可(kě)以縮減為(wèi)3個(gè)。
可(kě)能(néng)有(yǒu±σ)人(rén)很(hěn)快(kuài)會★(huì)有(yǒu)疑問(wèn),按照(zhào)等價輸入數(shù)據進行(xíng)λ✘測試,會(huì)不(bù)會(huì)有(yǒu)遺漏呢✔§ (ne)?
沒錯(cuò),尤其是(shì)邊界值處很(®×∑hěn)容易出錯(cuò)。這(zhè)就(jiù)是(shì)第二個(π★₽∏gè)方法要(yào)解決的(de)問(wèn)題。
2.3.2 邊λβ↓§界值法
仍然以上(s•←'✔hàng)一(yī)個(gè)案例展開(kāi)。使用(yòng)邊界值法的(de)話(huà),我們可(kě)φ¶♠為(wèi)等價類劃分(fēn)法定義的(de)測試用(yòng)例作(zuò)如(rú)下(xi δà)補充:
& ≈¶nbsp;- 剛好(hǎo)在邊界(1,100)
- ↕σ©∏剛好(hǎo)在邊界以下(xià)(0,99)
- 剛剛越過邊界(2,101ε♠σ)
Ω¶¶ 經過兩種方法的(de)結合,缺陷發現(xiàn)的(de)能(néng)力會(huì)進一(y÷∏≠ī)步提高(gāo)。
∞ 2.4 單元(代碼覆蓋度)測試
單元(代碼功能(néng))測試完成後,夠了(le)嗎<βδ(ma)?不(bù)夠。
≈ 我們沒測出bug,代表的(de)不(bù)是(sh↑₩ì)軟件(jiàn)沒bug,而是(shì)沒測夠。
沒測夠的(de)典型表現(♦©€xiàn)是(shì)測試用(yòng)例對(duì)代碼₽γ≈的(de)覆蓋程度不(bù)足,這(zhè)就(jiù)是(sh"£ì)本節要(yào)處理(lǐ)的(de)問(wèn)題。
主要(yào)的(deπ÷)代碼覆蓋度測試類型包括以下(xià)4種,嚴格程度從(cóng)上(shàng)到(dào)下(xαφià)依次增強:
-  §Ω;語句覆蓋(Statement Coverage):這(zhè)是(shì)最基本的(de)覆蓋度類型,它确保每個(gè)代碼語句至少(shǎo)執行(xíng)一(y ↑ī)次,100%的(de)語句覆蓋率可(kě)以保證沒有(yǒu)死代碼,屬于入門&₹(mén)級别的(de)測試。
- 分(fēn)支覆蓋(Branch Coverage):分(fēn)支覆蓋确保每個(gè)分(fēn)支語句(通(tōng)常是(shì)if語句) σπ←都(dōu)被覆蓋到(dào),即每個(gè)分(fēn)支的(dπ¶e)真和(hé)假兩種情況都(dōu)被測試到(dào),有(yǒu)助于揭示一(yī)些(xiē)邏輯錯(cuò)誤,如(rú)if ★¶←a and b then...,用(yòng)例為(wèi)a真+b真(分(fαλ→ēn)支為(wèi)真)、a真+b假(分(fēn)支為(w♥¶èi)假,與其他(tā)條件(jiàn)組合等價)即可(♥kě)100%。
  λ;- 條件(jiàn)覆蓋(Condition Coverage):條件(jiàn)覆蓋要(yào)求每個(gδσè)分(fēn)支語句的(de)每個(gè)條件(jiàn)都(dōu)§δ被覆蓋,即每個(gè)條件(jiàn)的(de)真和(hé)假兩種情況都(dōu)被測試到(dào),它比分(fēn)支覆蓋更為(wèi)嚴格,因為(δ λwèi)它會(huì)關注條件(jiàn)的(de)組合覆蓋,如(rú)if ∑↔a and b then...,用(yòng)例為(w≈±≈èi)a真+b真、a真+b假、a假+b真、a假+b假才可(kě)100%。
-&nbsβ↔←p;修改條件(jiàn)/判定組合覆蓋(Modified Condition/Decision Combination Coverage):這(zhè)一(yī)級别的(de)覆蓋要(yào≠σΩ∑)求同時(shí)滿足條件(jiàn)覆蓋和(hé)判定覆蓋,以确保條件(jiàn)和(hé)判定∏≤之間(jiān)的(de)組合覆蓋,是(shì)一(yī)種更加嚴格的(de)覆蓋度測試。
不(bù)同的(de$$→ε)項目和(hé)産品可(kě)能(néng)需要(∑γ₽yào)不(bù)同類型的(de)代碼覆蓋度測試。
通(tōng)常,基礎的(de)覆蓋度(如"σ(rú)語句覆蓋和(hé)分(fēn)支覆蓋)是(shì)必要(yào)的(de≈α)起點,而在需要(yào)更高(gāo)可ε♠↔(kě)靠性和(hé)安全性的(de)項目中♥®φ$,可(kě)能(néng)會(huì)選擇更嚴格的(♥ ÷↓de)MC/DC覆蓋度,比如(rú),涉及ASIL D的(de)模塊。
3 單元測試意義的(de)思考
說(shuō)意義的(de)話(huà),我→&"₩們可(kě)以很(hěn)快(kuài)說(s★÷✘huō)出一(yī)大(dà)堆,bug提前暴露、提升軟件(jiàn)質量、軟件(jiàn)更加健壯、利于↓✘重構、清除技(jì)術(shù)債務、積累組織資産......
問(wèn)題在于,在不(bù)好(Ω hǎo)言明(míng)的(de)價值和(hé)巨大(dà)的(de)交付壓力之下 ≠ε(xià),單元測試太容易被權衡掉了(le),誰還(hái)沒有(yǒu)個(gè)意義呢(n•<γe)?
實際上(shàng),管中窺豹,對(duì)這(zh✔δè)類重要(yào)但(dàn)不(bù)緊急事(shì)情的(de)意義的(de)探討(t♣≠ǎo)會(huì)折射出很(hěn)多(du♠♦↔ō)面的(de)信息,比如(rú)下(xià)面這(zhè)個(gè)算(suàn)式。
自(zì)動化(≤♦huà)的(de)程度+對(duì)軟件(jiàn)的(de)理(lǐ)解+産品的(de)競争∑←★力+公司的(de)文(wén)化(huà)+行(xíng)業(yè)的(de)生(shēng)态=單元測試的(de)意義
4 全文(wén)小(xiǎo)結
本文(wén)∏¥¶÷主要(yào)在講單元測試的(de)一(≠₹yī)些(xiē)基本概念和(hé)應用(yòng)場(chǎng)景。
首先,從(cóng)←ε是(shì)否執行(xíng)軟件(jiàn)、是(shì)否關←×∑注內(nèi)部代碼和(hé)汽車(chē)>πε€軟件(jiàn)分(fēn)層集成這(zhè)3個(gè)方面解釋了(le¶&£←)單元測試的(de)特點。進而,引申出汽車(chē)軟件(jiàn)單元測試的(de)概念。
接著(zhe),将單元測試細分(fēn)為'₽$(wèi)代碼評審、靜(jìng)态分(fēn)析、代碼功能(néng)測試、代碼€$λ→覆蓋度測試,并分(fēn)别進行(xíng)了(le)描述。₽♦
由于單¥$元測試離(lí)客戶需求太遠(yuǎn),往往被務實的(de)我們忽略,如(rú)何看(kàn £φε)待其價值需要(yào)探討(tǎo),第3小(xiǎo)節對(duì)此✘">≠做(zuò)了(le)簡單分(fēn)析₹₹ ↕。
5 寫在最後
不(bù)隻是(shì)單元測試ε™,軟件(jiàn)大(dà)舉進入汽車(chē)行(xíng)業β★∏(yè)的(de)過程中,未來(lái)無形不(bù)可(kě)見(jiàn)和(hé)↓>α"當下(xià)有(yǒu)形可(kě)見(jiàn)的(de)價值沖突持 ↓續在上(shàng)演。
如(rú)何把握向左還(hái)是(shì)向右的→(de)分(fēn)寸始終是(shì)一(yī)個(gè)巨大>ε׶(dà)的(de)決策考驗。
轉自(zì)汽車(chē)ECU開(kāi)發