C++組件測試及應用 — 基於Tessy的測試技術漫談

        編者按:隨着行業軟件的安全性關注度遞增,在產品測試初期開展全面單元/集成測試逐漸成爲了開發測試過程中關鍵環節,它將有助於儘早發現隱患,降低開發成本以及更加充分的功能驗證。ISO26262及ASPICE中同樣對單元/集成測試的實施提出了相應的要求。針對代碼的單元測試,要求對程序中每個獨立單元開展功能測試,而幾個層次結構的單元組合,如果有明確的功能,也可以把該單元組合稱爲模塊。對於集成測試,要求針對具備完整功能的模塊進行測試,此處具有完整功能的模塊,我們可以稱爲組件,並且通過增式測試的方式逐漸實現各組件的組合測試,因此,集成測試也可以看作是針對這些組件的功能和組件組合功能進行綜合驗證的過程。

         此文章來源於Tessy原廠Hitex於11月底發佈的白皮書《Component Testing of Test Objects in C++ ——Writing scenarios for integration testing in TESSY》。

1 從單元到組件

•  1.1測試對象的類型

        我們將基於測試對象類型討論“單元測試”、“模塊測試”、“集成測試”和“組件測試”,側重介紹時序的組件測試(假設軟件是C或者C++開發)。

       1.1.1獨立單元

         單個函數是C語言程序中最小的合理測試對象,通常被認爲是一個單元。如果編程語言是C++,那麼將方法視爲一個單元。

         單元測試是基於被測單元接口(即輸入和輸出)開展的功能驗證。開展單元測試時,會實際編譯執行被測程序,如果被測試的“單元”調用了其他函數,可以通過創建樁函數對調用的函數進行替換以保證測試的順利進行,提高測試效率。

       1.1.2 具有層次結構的單元

        具有層次結構的多個單元可以以一種類似於單個單元測試的方式開展,將頂層單元作爲測試對象,關注整體功能,被調用單元看作內部實現,針對整體的輸入輸出開展測試。 


C++組件測試1.jpg

Fig.1 將頂層單元作爲測試對象的單元層次結構


         從技術角度,這可以通過不使用樁函數替換被調用單元實現。仍可以像上面那樣將其視爲單元測試,只不過是更大的單元。

         這也可以看作是單元層次結構中的集成測試,因爲從某種程度上,它們必須能正確地一起工作才能通過測試。這樣的單元層次結構也能被稱爲模塊(Module),但是我不想用這個術語,因爲這可能會與C/C++程序的源模塊概念混淆。(一個C源模塊不能直接作爲模塊測試對象,因爲它是依照語法定義的,而用於模塊測試的module通常是按照語義定義的。)         多個單元層次結構的測試在技術上與單個單元測試非常類似,由於當前文檔主題是組件測試,因此進一步討論的是功能層次結構的測試。

       1.1.3 相互作用且無時序關係的單元

        與單元層次結構相反,在接下來,我們認爲單元之間不一定具有調用關係,然而,我們假設這些單元相互協同工作,例如操作公共數據以實現一個共同目標。

         衆所周知的抽象數據類型“棧(stack)”,及其push和pop操作就是一個很淺顯易明的例子。pop和push操作的獨立測試是單元測試,但是仍需要進行必要的集成測試。集成測試由一系列pop和push操作組成。該測試用例的輸入由棧的初始內容和push操作的參數值組成,結果是pop操作的返回值和棧的最終狀態。如果push和pop操作可能導致對單元的額外調用,例如對棧溢出/下溢的錯誤處理單元的調用,這些調用也屬於集成測試用例的預期結果。


 C++組件測試2.jpg

Fig.2 對於抽象數據類型“棧(stack)”的push和pop操作,單元測試是不充分的


         “模塊(Module)”這個術語可能更適合於這樣一個協作單元集合,但我更喜歡用“組件(component)”這個術語,因爲它的含義與C/C++源模塊不一樣。 


C++組件測試3.jpg

Fig.3 組件的內部結構及其與外部的接口


         “組件”內含的“單元”中,必須至少有一個具備從組件外部調用以驅動組件的功能。通常一個組件的幾個單元來自外部調用,我們稱這些單元爲“組件函數”或“組件單元”。對一個組件的測試不再由(一個或多個)對單個單元的調用(如上面兩部分所述)組成,而是由對(不同的)組件單元的一系列調用組成。對組件單元的調用將激活組件,與單個單元測試一樣,組件的測試用例也包括輸入和輸出數據(組件的變量和被調用組件單元的參數)。組件可能具有內部單元,這些單元不能從組件外部調用,只能通過組件內部的函數調用獲取。

         內部單元所做的工作(如果有的話)與組件測試無關,因此組件測試中,是將整個組件看作一個黑盒。然而,與組件測試結果相關的是從組件內部到其他組件中(可調用的)單元的調用序列。這涉及到調用的數量、調用的順序和調用傳遞給其他組件的參數。

         很顯然,組件中單元的功能以及它們之間的接口大部分情況下是通過組件測試來實現驗證。因此,組件測試可以看作是對組件中單元的集成測試。


 C++組件測試4.png


       1.1.4 相互作用且有時序關係的單元

         在上一節中,時序不是重點,無論是組件的激發調用時長,還是組件的激發調用與另一個組件的結果調用之間的時長。然而,這是一個檢查收到激發調用後響應是否足夠快的重要測試,即在定的時間範圍內。

         爲了能夠在模擬環境中測試組件的時序行爲,需要有一個模擬的時間基數。這意味着組件內部的某個單元在已知的等距時間內被調用(例如每10ms),通常組件在實時操作系統(RTOS)的控制下執行並使用time-slicing(例如OSEK)就是這種情況,但一個簡單的中斷驅動應用程序通常也符合這種要求。

         對該單元的調用代表組件的“心跳(heartbeat)”,它們爲測試組件的時序行爲提供了一個(模擬的)時間參考。心跳函數通常被稱爲“handler function”或“work task”或簡單稱爲“tick”。


 C++組件測試5.jpg

Fig.4 如果心跳函數存在,則可以測試時序行爲 


2 C++棧的例子

•  2.1 介紹

        正如前面所介紹的,抽象數據類型棧是一個典型的例子,在Tessy中進行集成測試需要使用Tessy的組件測試功能(在場景編輯器透視圖中可以訪問)來完成。而且,push和pop不相互調用,而是在公共數據(棧)上通信,因此,單純的單元測試技術手段是不適用的,因爲它們要求單元有一個單一的入口點,即單元測試側重測試一個單一函數/方法。 


C++組件測試6.jpg

Fig.5 stack.push和stack.pop不互相調用,需要集成測試


  •  2.2 測試對象源代碼


 C++組件測試7.jpg

Fig.6  測試對象的源碼(stack.cpp)


         注:源代碼最後三行不屬於堆棧的實現,而是Tessy所要求的,由於使用了#ifdef,所以tick()函數只在源文件被Tessy處理時纔出現。


 •  2.3 Tessy準備工作

        測試環境選擇GCC(C++),測試類型選擇Component,導入代碼。


 C++組件測試8.jpg

Fig.7 選擇編譯環境


 •  2.4 接口設置

        新建一個變量my_stack作爲實例化的對象。


 C++組件測試9.jpg

Fig.8 接口設置

 •  2.5 測試用例設計和執行

        創建第一個測試用例:驗證入棧出棧操作。


 C++組件測試10.jpg

Fig.9 場景1的設計和執行結果


         創建第二個測試用例:該用例目的是驗證棧下溢情況下的功能實現。

        在Edit Test Execution Settings界面勾選Test Cases Separately分別執行兩個場景,場景及結果如下圖所示。 


C++組件測試11.jpg

Fig.10 場景2的設計和執行結果


         在SCE的用例設計界面中,針對指針的操作如下:爲指針*arr創建一個對象,指定其爲一個長度爲4的數組;指向這個目標的指針由Tessy分配給對象my_stack中的變量arr,也就是說,分配的內存代替了由測試對象的構造函數分配的內存,由於此前將指向指針對象的接口設置爲INOUT,所以該對象同時出現在Inputs和Outputs列項中。 


C++組件測試12.jpg

Fig.11 爲指針*arr創建一個對象 


C++組件測試13.jpg

Fig.12 場景2 SCE執行實際結果


微信二維碼推廣.jpg

經緯恆潤

北京市海淀區知春路7號致真大廈D座6層

電話:010-64840808

郵箱:[email protected]

網址:www.hirain.com


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章