C C 單元自動化測試解決方案實踐

2022-10-11 15:54:12 字數 3820 閱讀 6363

vivo 網際網路伺服器團隊 - li qingxin

c/c++ 開發效率一直被業內開發人員詬病,單元測試開發效率也是如此,以至於開發人員不願花時間來寫單元測試。那麼我們是不是可以通過改善編寫單元測試的效率來提公升專案的測試用例覆蓋率?

上圖展示了c/c++單元測試的基本流程,在日常開發過程中寫單元測試是一項比較大工程量的事情,c/c++ 目前單元測試**都需要自己手動寫,而且對於一些私有方法打樁就更加麻煩。

目前業內無開源的自動化測試框架或者工具,倒是有一些商業的自動測試工具,下圖展示了我們自動化測試工具及單元測試庫:

即使開源界有gtest等測試庫的支援,我們仍然需要編寫大量的單元測試用例**。對於一些private、protected的類方法,編寫單元測試用例的效率就更低,需要手動打樁(mock)。同時我們分析測試用例發現,存在很多邊界的用例,它們基本上都是很固定或者有一定模式,比如int 最大最小值等。

如何改善編寫單元測試的效率,提公升c/c++同學開發效率以及程式質量?我們可以通過提取原始檔中的函式、類等資訊,然後生成對應的單元測試用例。自動生成用例時需要依賴函式的宣告、類的宣告等資訊,那麼我們應該如何獲取這些資訊呢?

例如:如下的函式定義:

void test(int arg) {}

我們希望能夠從上面的函式定義中得到函式的返回值型別、函式名稱、函式引數型別、函式作用域。通常我們可以通過以下幾種方式得到:

無奈c/c++ 格式比較複雜能夠雖然能夠使用多種組合來獲取對應的函式宣告等資訊:

void test(int arg){}

void test1(template> arg,...){}

void test2(int(*func)(int ,float,...),template> arg2){}

那麼就需要寫一系列的正規表示式:

這當然是一種很好的方式,但是工作量巨大,相當於實現乙個具備詞法、語法分析器簡易版本的編譯器,而且要適配不同的語法格式,雖然bison可以解決上述的如何判斷語法是否正確問題,但是仍然很複雜。

通常我們了解到的gcc編譯的過程是以下四個階段:

原始檔->預處理->編譯->彙編→鏈結

上圖展示了gcc處理原始碼及其他優化過程,在前端部分生成的generic 語言是gcc編譯過程中為原始碼生成的一種與原始碼語言無關的抽象語法表現形式(ast)。既然gcc編譯過程中生成了ast樹,那麼我們可以通過gcc外掛程式來提取gcc 前端生成的抽象語法樹關鍵資訊比如函式返回值、函式名稱、引數型別等。總體難度也很高,一方面業內可參考資料很少,只能通過分析gcc的原始碼來分析ast語法樹上的各個節點描述。

本文所描述的自動化生成單元測試用例的解決方案(我們稱之為tu:translate unit,後文統稱為tu)就是基於方法3來實現的,下面我們先來看看我們的自動化測試用例解決方案的效果展示。

在該用例中我們不需要修改任何業務**就能夠為業務**生成邊界測試用例,而且函式引數可邊界值實現全排列,大大降低用例遺漏風險。大家可能發現這種沒有做任何修改生成的用例是沒有斷言的,雖然沒有斷言,它仍然能夠幫助發現單元是否會存在邊界值引起coredump。

那麼如果想要給他加上斷言、mock函式,是否沒有辦法呢?通過c++11 新的屬性語法,只需要在方法宣告或者定義時新增下根據tu的格式新增斷言即可,對業務邏輯無侵入。

很多情況下預設生成的邊界測試用例還不能覆蓋到核心邏輯,所以我們也提供tu::case 來給使用者自定義自己的測試用例及斷言。比如有乙個int foo (int x,long y) 方法,現在想新增乙個測試用例返回值123,函式實參1,1000,那麼只要在函式宣告前加入,以下**即可:

開發過程中我們也常需要對某個方法進行mock(即對原有方法設定乙個臨時代替方法並且呼叫方式保持一致),比如某個函式訪問redis、db這種情況下進行單元測試往往需要對這些方法進行mock,方便其他函式呼叫進行單元測試,為了方便進行單元測試我們往往會對其進行mock,所以為了方便開發人員進行快速的mock,所以我們提供了tu::mock 的註解幫助開發同學快速的定義註解,然後tu會自動生成對應的mock函式。例如:現在給foo_read 方法mock乙個函式,讓mock的函式返回10:

generic、gimple和rtl三者構成了gcc中間語言的全部,它們以gimple為核心,由generic承上,由rtl啟下,在原始檔和目標指令之間的鴻溝之上構建了乙個三層的過渡。

gcc在語法分析過程中,所有識別出來的語言部件都用乙個叫tree的變數儲存著。這個tree就是gcc語法樹(ast),這個過程叫做generic。實際上它也是gcc的符號表,因為變數名、型別等等這些資訊都由tree關聯起來。

下面我們通過gcc編譯選項來看下gcc的ast表現形式:

gcc 可以通過新增編譯選項-fdump-tree-all 來生成ast 樹,ast樹檔案內容如下:

ast 各個型別描述可以參考:

如上圖所示,我們通過使用不同的外掛程式收集被測試原始檔的ast資訊、標頭檔案資訊、函式註解(屬性),將這些重要資訊儲存起來。gcc將使用者註冊外掛程式事件儲存到陣列中:

然後在編譯構建過程中到就會去查詢對應的事件有沒有設定**方法如果設定則進行呼叫,tu主要使用以下幾種外掛程式:

gcc 支援的所有外掛程式型別如下圖所示:(摘自gcc 6.3.0 原始碼)

如果僅僅只是做邊界測試那麼僅需要修改構建的指令碼比如cmake 新增對應的外掛程式引數即可。

接入簡單、邊界單元測試可以做到業務**0修改

函式引數可邊界值實現全排列,大大降低用例遺漏風險、減少大量重複性的工作

快速生成使用者自定義用例、mock方法等

2、文章中還主要介紹了tu的功能特點以及基於gcc-ast的實現自動生成測試用例的解決方案。

tu解決方案目前在構建時能夠自動生成測試用例已經極大降低了單元測試門檻提公升單元測試覆蓋率,未來我們也希望能夠把tu與ide相結合,探索更高效便捷的使用方式,通過更加便捷的方式生成指定方法的測試用例。比如通過在函式、方法上,通過快捷鍵生成當前方法的測試用例等。

gcc plugins

functions for c++ (gnu compiler collection (gcc) internals)

測試方案 OBC DCDC自動化測試解決方案

obc 車載充電機 和dcdc 直流 直流變換器 是電動汽車的核心部件,dcdc和obc的功能質量對於整車的效能和安全性至關重要。在obc和dcdc,以及整車開發測試過程中,需要對obc和dcdc進行功能和效能方面進行全面的測試。根據客戶需求,意昂神州提供靈活的測試系統解決方案 測試系統支援的測試功...

自動化測試中自動化切換網路 解決方案

自動化測試中自動化切換網路 解決方案 思路 使用方式 關閉wifi,切換到4g網路 測試手機預設流量是開著的 adb shell am force stop com.steinwurf.adbjoinwifi adb shell am start n com.steinwurf.adbjoinwif...

自動化技術解決方案

1.web自動化 借助selenium自動化測試框架,以及phantomjs無gui瀏覽器,可以實現web的一些自動化操作。selenium,可以借助網頁中的css,id等特徵,精準地識別出界面上的按鈕 輸入框等。我目前發現的唯一的不太友好之處是,當識別不到元素時候,有時候設定強制等待一兩秒時間就可...