擴充套件 JUnit 測試並行程式

2021-08-24 18:40:44 字數 3592 閱讀 1111

測試並行程式與以往有什麼不同 ?

隨著多核的普及,並行程式的開發已經提上日程。相對序列程式而言,並行程式更有可能出錯。一方面,並行程式的執行序列具有很強的隨機性,執行緒交錯執行的序列可能每次都不一樣,而只要乙個序列有問題,整個程式就是不正確的。另一方面,並行程式對大多數程式設計師來說,都是乙個新的領域,經驗相對較少,這是容易出錯的另外乙個因素。

既然如此,我們就更需要仔細的測試我們的並行程式和元件了。目前已經有一些 junit 擴充套件可以建立多個執行緒,同時執行多個測試用例,從而加快測試用例集的執行速度,如 p-unit 。但對於測試並行程式和元件,這些功能並不能滿足所有的需求。因為開發人員通常希望可以精確地控制多個執行緒之間的同步。

與測試順序程式相同,我們希望能在測試並行操作之前,首先準備一些測試資料。然後,啟動多個執行緒測試執行不同的操作。最後,等待所有執行緒結束之後,檢驗結果的正確性。在第二階段中,多個執行緒能以任意的次序交錯執行。結果的正確性檢查應與執行緒的執行測序無關。

標準 junit 只捕捉來自主線程的 exception 。而其他執行緒中產生的 exception 則會安靜地被忽略掉,使得我們在子執行緒執行出錯的情況下仍舊能得到「 green bar 」。這顯然不是程式設計師喜歡的測試行為,我們希望測試結果能正確地反映所有執行緒的執行結果。

這種用於並行程式的測試模式會在測試並行程式時會不斷的重複。如果開發人員每次都需要重複建立這些框架,不僅繁瑣,而且容易引入錯誤。通過使用以下介紹的簡單擴充套件,可以使並行程式的測試變得和順序程式一樣簡單。這種擴充套件並不影響 junit 的其他特性以及各種 ide 的 junit 外掛程式的使用。

首先,我們給出乙個使用新擴充套件進行並行測試的例子。

例 1. 使用 junit 擴充套件進行並行測試

/** * @author zhi gan * */ @runwith(parallelized.class) @parallelsetting(threadnumber = ) public class testthreaded @test public void donothing() @initfor("testthread") public void putsomedata(int size) @threadedpublic void testthread(int rank, int size) @checkfor("testthread") public void checkresult(int size) public static void main(string args) }

如果我們在 eclipse 中執行測試,那麼測試完畢之後的 junit 檢視如下所示:

圖 1. 並行測試的完成結果

接下來,我們模擬子執行緒在執行時丟擲異常。

例 2. 子執行緒執行時異常

/** * @author zhi gan * */ @runwith(parallelized.class) @parallelsetting(threadnumber = ) public class testthreaded @test public void donothing() @initfor("testthread") public void putsomedata(int size) @threadedpublic void testthread(int rank, int size) @checkfor("testthread") public void checkresult(int size) public static void main(string args) }

如果我們在 eclipse 中執行測試,那麼測試完畢之後的 junit 檢視如下所示:

圖 2. 並行測試的完成結果

從上圖可以看出,我們的並行測試用例通過了測試,並且它們在使用不同執行緒執行時都能正常的工作。而序列的測試方法 (donothing) 的執行結果則完全和之前一樣工作正常。也就是說,序列和並行測試可以在乙個測試類中同時出現。

annotation 詳細說明

表 1. 擴充套件的 annotation 說明

名稱引數

使用物件

備註parallelsetting

threadnum: 用於指定執行緒數目。通常我們希望能使用乙個陣列指定多個值,這樣,我們可以了解程式是否在單執行緒,較少執行緒,以及大量執行緒的情況下是否工作正常。

用於整個 testcase 來指定測試所用的並行設定

用於指定整個 testcase 的並行設定

initfor

指定此方法服務的測試方法

用於指定初始化方法所服務的並行測試方法

threaded

無引數,或定義與 @test 相容的引數

用於乙個具有兩個 int 型別的測試方法。測試過程中,測試框架將會線程式號以及執行緒總數通過方法的引數傳遞進來。這有點類似於 mpi 的約定。

指明乙個方法為並行測試方法,相當於 junit 原有的 @test 注釋

checkfor

乙個字串引數,用於指定需要被驗證的並行測試方法。

乙個 threaded 修飾的方法

指明乙個方法用於檢測並行執行的結果 . 我們不能在 threaded 方法中直接檢查,因為其他執行緒的測試也許還沒有結束。

擴充套件 junit 的過程說明

歸功於 junit 的靈活的內部架構,只要遵循 junit 的標準,我們就能夠輕鬆的擴充套件 junit 的功能。而且遵循標準還意味著我們的擴充套件能無縫的利用社群對 junit 的廣泛支援。例如,我們沒有編寫任何 eclipse 外掛程式,但是我們的測試結果能自然的在 eclipse 中通過精心設計的 gui 進行展現。

言歸正傳,我們擴充套件 junit 的過程主要由以下過程組成:

生成 annotation 的定義,包括:@threaded, @initfor, @check, @parallelsetting

生成 testclassrunner 的子類 parallelized 並在其中實現執行自定義測試的邏輯

生成 testmethodrunner 的子類供 parallelized 類使用

在實現 threadedmethodrunner 時,我們最開始在類 threadedmethodrunner 使用了 thread 類的 setdefaultuncaughtexceptionhandler 來捕獲異常。然後將異常封裝到主線程。而目前的版本則利用了 executor 來執行多執行緒測試。由於 jdk 中的 future 已經提供了類似的能力,所以我們不需要再關心異常的正確傳遞問題了。 junit 能準確的列印出並行測試中產生的異常資訊,這也意味著我們可以使用 junit 提供的 assert 功能了。

結論隨著多核平台逐漸成為主流,開發人員不可避免地需要開發和測試並行應用。本文通過使用 annotation 擴充套件 junit,使其可以更方便地支援「準備資料——多執行緒執行——檢查結果」三階段的並行測試模式,減少開發人員手工建立執行緒和同步的繁瑣工作。並且可以使 junit 支援從子執行緒中捕獲測試錯誤,正確地在 eclipse 等 ide 中顯示測試結果。

並行程式除錯 測試與模型檢測

並行程式除錯 測試與模型檢測 並行程式除錯的挑戰 1 由於不能確定不同執行緒的執行順序,導致可能的執行路徑發生組合 2 使用模型檢驗程式正確性能以應用到分布式系統上。名詞解釋 確定性重放 通過記錄系統中不確定性事件的發生順序,在重放階段按照記錄的順序執行相關事件,使得重放階段與記錄階段的執行具有相同...

併發程式與並行程式

併發程式是指可以被同時發起執行的程式 並行程式被設計成可以在並行的硬體上執行的併發程式。併發程式代表了所有可以實現並發行為的程式,它是乙個寬泛的概念,其中包含了並行程式。inter process communication 程序間通訊 go支援的ipc方法有管道 訊號和socket.程序 我們把乙...

Java並行程式基礎

程序是計算機中的程式關於某資料集合上的一次運動活動,是系統進行資源分配的基礎單位。程序是執行緒的容器。程式是指令 資料及其組織形式的描述,程序是程式的實體。執行緒的所有狀態都在thread的state列舉中 public enum state t1.start 也可以使用runnable介面來實現相...