unity單元測試框架的工作原理,及隱含問題
unity單元測試框架的工作原理,及隱含問題
unity 是 github 上的一個開源測試框架,能夠很方便的移植到各種不同的嵌入式平臺中。unity的主要實現依賴 setjmp 與 longjmp 及 printf 函式。unity 的實現中將不同的測試情況封裝為不同的巨集,通過呼叫相應的巨集就能夠完成對輸入條件進行測試。
在測試開始時,unity 會呼叫 setjmp 儲存當前棧幀,然後執行初始化任務(如果setUp函式被重寫),完成後執行測試函式主體,在測試函式中可能有數量不等的巨集的使用,當一個測試條件失敗後,unity 生成錯誤資訊,呼叫 longjmp,以不同的返回值跳轉到 setjmp 預先設定的位置,然後列印資訊,繼續執行其它的測試demo。這也就是說當一個條件不滿足後,該條件後邊的程式碼將不會再執行,這符合測試的基礎邏輯,但是在某種情況下可能會造成極其嚴重的問題。
首先 setjmp 與 longjmp 棧跳轉函式本身就有潛在的問題。setjmp 儲存的上下文資訊中所有儲存在記憶體中的變數都與 longjmp 呼叫後的值相同。在 cpu 或浮點暫存器中儲存的變數將會恢復到 setjmp 呼叫時的值。如果你忽略了這點,而且你的程式恰好依賴這些儲存在 cpu 或浮點暫存器中的變數,那麼程式的執行將產生異常。
setjmp 與 longjmp 自身的問題被 unity 的測試程式碼繼承,因此這也是 unity 中潛在的問題。不過除了這個問題之外,還存在著一種更為致命的問題,不過這個問題是完全可以避免的。
假設我們有一個測試主任務,我們在測試主任務的執行函式中依次呼叫測試函式來進行測試。當某個需要在子任務中執行的測試條件失敗時,unity 將會呼叫 longjmp 棧跳轉到 setjmp 的位置,而 setjmp 在測試主任務中執行,也就是說我們現在從一個任務直接跳轉到了另外一個任務。這裡存在的問題是子任務並沒有被殺死,它只是暫時退出了 cpu ,不久之後它還能夠再次執行,但該子任務後面的執行程式碼依賴前面條件的正確達成,因此就會造成各種異常的結果。
避免這種方式的方案也很簡單—不要在任務之間執行棧跳轉。