【嵌入式单元测试】C语言单元测试框架搭建
cmocka
- cmocka交叉編譯
- 源碼下載
- 編譯準備
- 源碼修改
- 指定編譯器
- 編譯
- cmocka使用示例
- 常見問題
- 參考
單元測試框架是一個軟件包,它能夠讓開發者比較方便的表達產品代碼需要表現出什么樣的行為。單元測試框架提供了一個自動化單元測試的解決方案,讓開發者把更多的精力放在測試用例的設計的編寫上,而不用花精力考慮如何對測試用例進行組織。
cmocka是一個優雅的C語言單元測試框架,支持模擬對象。它只需要標準的C庫,適用于各種計算平臺(Linux、windows,以及嵌入式)。
理論上來說,cmocka可以支持任何使用標準C庫的交叉編譯器。
本文將介紹如何在嵌入式環境(交叉編譯)搭建cmocka單元測試環境,以及cmocka的簡單使用示例。
cmocka交叉編譯
源碼下載
目前最新的1.1.5版本,對于嵌入式環境,我們需要下載源碼進行交叉編譯
cmocka1.1源碼下載地址
這里以cmocka-1.1.5.tar.xz為例。
編譯準備
將上述源碼在linux環境中解壓,并在源碼同級目錄新建編譯目錄build_dir
cmocka-1.1.5內容如下:
源碼修改
進入cmocka-1.1.5源碼目錄,修改頂層CMakeLists.txt,將如下行注釋掉。
doc組件需要特定的庫支持,嵌入式環境一般沒有這個庫,而且這個只是生成代碼注釋,對功能沒有影響,所以將其注釋。
指定編譯器
接下來在build_dir目錄的同級目錄新建配置文件arm64_setup.cmake(文件名隨意)
文件內容如下:
- CMAKE_SYSTEM_NAME 指定嵌入式系統類型
- CMAKE_SYSTEM_PROCESSOR 指定嵌入式平臺
- tools 交叉編譯器路徑(以實際路徑為準)
- CMAKE_C_COMPILER C交叉編譯器
- CMAKE_CXX_COMPILER C++交叉編譯器
編譯
編譯需要進入build_dir目錄,先執行如下命令生成必要的配置和makefile文件
$ cd build_dir $ cmake -DCMAKE_TOOLCHAIN_FILE=../arm64_setup.cmake -DBUILD_STATIC_LIB=ON ../cmocka-1.1.5/- -DCMAKE_TOOLCHAIN_FILE是指定剛剛創建的編譯器配置文件
- -DBUILD_STATIC_LIB=ON 是編譯生成靜態庫,去掉這句只會生成動態庫
- ../cmocka-1.1.5/指定cmocka源碼目錄
如果上述步驟沒有錯誤,那么在build_dir應該會生成若干目錄和文件,其中就包括makefile,接下來執行make 編譯即可。
$ make出現下列提示表示編譯成功:
Scanning dependencies of target cmocka [ 4%] Building C object src/CMakeFiles/cmocka.dir/cmocka.c.o ...... [100%] Linking C executable test_uptime [100%] Built target test_uptime如果需要clean,直接在build_dir目錄執行make clean是不行的,因為Cmake不支持。最簡單的方式就是把build_dir目錄手動清空即可。
編譯完成后查看build_dir/src,會生成我們需要的動態庫或者靜態庫.
使用file指令可以看到這個動態庫是ARM aarch64平臺的,表明我們交叉編譯成功了。
另外,build_dir/example目錄下也會生成一些示例demo,可以直接在開發板上運行。
$ build_dir/example$ ls allocate_module_test CMakeFiles Makefile assert_macro_test cmake_install.cmake mock assert_module_test CTestTestfile.cmake simple_test $ file simple_test simple_test: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-aarch64.so.1, with debug_info, not stripped有了libcmocka,在加上源碼中的cmocka.h,我就可以利用cmocka提供的API編譯我們自己的單元測試代碼了。
cmocka.h位于cmocka源碼的include目錄
cmocka使用示例
測試代碼如下:
$ tree hello/ hello/ ├── inc │ └── cmocka.h ├── libs │ ├── libcmocka.so │ └── libcmocka-static.a ├── makefile └── src└── hello_cmocka.c- libs文件夾主要存放庫文件,推薦使用libcmocka靜態庫,使用靜態庫的好處是編譯出的二進制文件在開發板上可以直接運行,如果是動態庫還需要開發板上也安裝這個動態庫,靜態庫的缺點就是編譯產物體積較大。
示例makefile文件如下:
#source file SOURCE += $(wildcard ./src/*.c) OBJS := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE)))TARGET := hello_cmocka#compile and lib parameter CC := aarch64-openwrt-linux-gcc LIBS := -lcmocka-static LDFLAGS := -L./libs DEFINES := INCLUDE := -I./inc/ CFLAGS := -g -Wno-unused-variable -O3 $(DEFINES) $(INCLUDE) CXXFLAGS:= $(CFLAGS) .PHONY: all : $(TARGET) objs : $(OBJS)clean :rm -fr ./src/*.orm -fr $(TARGET)$(TARGET) : $(OBJS)$(CC) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LIBS)示例hello_cmocka.c如下:
#include <stdarg.h> #include <stdio.h> #include <setjmp.h> #include <stddef.h> #include <stdint.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <cmocka.h>static int add(int a ,int b) {return a+b; }static char* print_string(int num) {switch(num){case 1: return "CASE1";case 2: return "CASE2";default: return "NOT SUPPORT";}return "NOT SUPPORT"; }static void test_demo1(void **state) {int ret = add(3,2); assert_int_equal(ret, 5);(void) state; } static void test_demo2(void **state) {int ret = add(3,2);assert_int_equal(ret, 0);(void) state; }static void test_demo3(void **state) {char *p = print_string(1);assert_string_equal(p, "CASE1");(void) state; }int main(void) {const struct CMUnitTest tests[] = {cmocka_unit_test(test_demo1),cmocka_unit_test(test_demo2),cmocka_unit_test(test_demo3),};return cmocka_run_group_tests(tests, NULL, NULL); }運行結果如下:
# ./hello_cmocka [==========] Running 3 test(s). [ RUN ] test_demo1 [ OK ] test_demo1 [ RUN ] test_demo2 [ ERROR ] --- 0x5 != 0 [ LINE ] --- src/hello_cmocka.c:46: error: Failure! [ FAILED ] test_demo2 [ RUN ] test_demo3 [ OK ] test_demo3 [==========] 3 test(s) run. [ PASSED ] 2 test(s). [ FAILED ] 1 test(s), listed below: [ FAILED ] test_demo21 FAILED TEST(S)提示test_demo2測試失敗,原因是0x5 != 0,test_demo2的預期結果是0,實際返回5,不符合預期,故測試失敗。
assert_int_equal()是判斷int類型結果,assert_string_equal()是判斷const char *類型的結果。除此之外,cmocka還提供了更多其他的測試API,請參考cmocka.h.
常見問題
cmocka源碼中uintptr_t定義和我們的交叉編譯器中的定義沖突了,這里只需要暫時把編譯器中的定義注釋掉,編譯完cmocka再改回來即可。
cmocka僅使用了標準C庫,它的跨平臺兼容性很好。因此,對于絕大多數的交叉編譯器應該都是支持的(除非你的編譯器版本很低,對C庫的支持不全)。
因此,交叉編譯cmocka源碼中遇到的編譯問題基本上都是C代碼問題,與平臺無關。
參考
- cmocka官網
- cmocka API介紹
總結
以上是生活随笔為你收集整理的【嵌入式单元测试】C语言单元测试框架搭建的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: stm32 模拟U盘IAP升级 与 FA
- 下一篇: FAT16文件系统之总结构分析(一)