EmbedC_TDD__1 Keil中搭建自動化單元測試框架Unity
1 什麼是Unity
Unity是一個全部用C實現的自動化測試框架。它由很少的幾個檔案構成。
自動化測試框架就是一個軟體包,它能讓程式設計師表達產品程式碼應該有什麼樣的行為。自動化測試單元測試框架的工作需要提供以下能力:
- 用於表述測試用例的通用語言
- 用於表述期望結果的通用語言
- 能夠使用產品程式碼所用的程式語言的功能
- 能夠把所有的工程、系統或者子系統的單元測試用例收集到一起。
- 一個能執行全部或者部分測試用例的機制
- 對於測試套件的成功和失敗給出明確的報告
- 對於失敗的測試給出詳細的報告
需要指出的是測試框架只是給我們實現了一套測試機制,具體的測試用例還需要我們自己編寫。
2 為什麼要使用Unity
使用Unity的好處將在另一篇博文中詳細介紹。請點選這裡檢視。
3 獲取Unity的原始碼
4 Unity原始碼目錄結構分析
目錄 | 內容 |
---|---|
src | 這個資料夾中包含unity.c、unity.h、unity_internals.h,這是最基本的Unity組成,有了這三個檔案你就可以開始編寫測試用例了 |
docs | Untiy的相關應用文件都在這裡,有條件同學建議都讀一下 |
auto | 簡化測試用例搭建的Ruby指令碼,沒研究過Ruby,暫時不知道咋用 |
examples | 參考測試例程 |
extras | 附加實現夾具的功能 |
test | Unity的所有的測試 |
5 在Keil中搭建Unity
5.1 將Unity原始碼新增到Kiel工程中
-
在工程檔案中新建Unity目錄,並拷貝從GitHub上下載下來的原始碼,如下圖:
-
在Keil已有的工程中新建Unity目錄,用於和Unity相關的原始碼實現,然後加入unity.c和unity_fixture.c。如下圖:
-
包含新新增的標頭檔案的路徑
-
在unity的原始碼examples中找到unity_config.h並放到我們工程的unity資料夾下。
-
編譯已有的keil工程,無錯誤無警告後繼續,有錯誤則檢測。
5.2 配置unity_config.h
開啟unity_config.h並配置,主要是為了配置一些資料型別和列印的重定向。我使用cm4核心定義的配置如下:
#define UNITY_EXCLUDE_LIMITS_H /* 呼叫limits.h, UINT_MAX和ULONG_MAX預設是32位*/
#define UNITY_EXCLUDE_STDINT_H /* */
#define UNITY_INT_WIDTH 32 /* int型變數是32位 */
#define UNITY_POINTER_WIDTH 32 /* 設定指標為32位 因為我們是32位系統 */
#define UNITY_INCLUDE_DOUBLE /**/
#define UNITY_OUTPUT_CHAR(a) fputc(a, stdout) /* 重定向輸出列印函式 */
#define UNITY_SUPPORT_WEAK __attribute__((weak)) /* 設定Unity中setup、teardown、suiteSetUp、suiteTearDown為弱函式如,果自己的工程中有setup函式Unity中自動無效而不會產生重定義問題。具體以原始碼中介紹為準。*/
其中比較重要的配置就是unity輸出的重定向了,這個函式會列印具體的unity的輸出資訊,如果我們現有的工程是使用串列埠輸出,則可以直接定向到串列埠輸出上,這裡我使用的是EventRecoder除錯工具,使用標準的printf輸出,所以直接重定向到了fputc上。
5.3 編寫測試用例
完成以上的步驟,我們就可以使用Unity了。仿照examples裡的例子,我們直接建立一個TestProductionCode_Runner.c檔案,該檔案包含了Unity的入口main函式。所以,對於我們工程的main函式來說,就不能這麼寫了,在完成相關的初始化後,必須退出,然後進入到Unity的main函式入口。改動如下:
#ifdef USING_UNITY_MAIN
int product_main(void)
#else
int main(void)
#endif
{
EventRecorderInitialize(EventRecordAll, 1U);
EventRecorderStart();
delay_init(168); //初始化延時函式
LED_Init(); //初始化LED埠
OLED_Init(); //初始化OLED
OLED_Clear();
OLED_ShowString(0,0,"0.96' OLED TEST",16);
printf("Hello EventRecord!\r\n");
#ifndef USING_UNITY_MAIN
while(1)
{
LED2 = 0;
LED3 = 1;
delay_ms(500);
LED2 = 1;
LED3 = 0;
delay_ms(500);
}
#endif
return 0;
}
5.3 Unity測試結果解析
如上所示,沒有訊息就是最好的訊息,如果全部測試通過,最後會列印OK,如果測試失敗,則會反饋失敗的原因和具體的失敗位置。
最後,工程原始碼請點選這裡獲取。