好久以前就想试用一下cmock,但一直没有做,汗。。。
今天想起来,赶紧试一下。
在官网上,下载安装包cmock_2_0_204.zip,方便的是,不需要编译和安装。不过cmock依赖于ruby,因此,得先安装一下ruby。
注:这个安装包中也包含了一个单元测试工具unity,在解开后的子目录vendor/unity/下。
例子概述:
4个文件:my_try.h、my_try.c、my_math.h、my_try_ut.c
my_try.h和my_try.c是我要测试的代码文件,功能很简单,就是封装调用my_math.h提供的接口。
比如,my_try.c中的函数my_add()会直接调用my_math.h提供的接口add()。
my_try_ut.c则是单元测试的代码,它利用cmock来实现my_math.h中接口的桩代码,比如add()。
这样就把测试重心放到我想要测试的my_try.c中来。
my_math.h的代码:
#ifndef _MY_MATH_ #define _MY_MATH_ int add(int a, int b); int sub(int a, int b); #endif
#ifndef _MY_TRY_ #define _MY_TRY_ int my_add(int a, int b); int my_sub(int a, int b); #endif
#include "my_math.h" #include "my_try.h" int my_add(int a, int b) { return add(a, b); } int my_sub(int a, int b) { return sub(a, b); }
my_try_ut.c的代码:
#include "unity.h" #include "my_try.h" #include "Mockmy_math.h" void setUp(void) { } void tearDown(void) { } void test_add() { add_ExpectAndReturn(1, 2, 2);//设置桩,让add(1,2)返回2 TEST_ASSERT_EQUAL(3, my_add(1, 2)); } void test_sub() { sub_ExpectAndReturn(1, 2, -1); TEST_ASSERT_EQUAL(-1, my_sub(1, 2)); }
CC = gcc CFLAGS = -g -Wall # base dir CMOCK_DIR = ../cmock/ CMOCK_SRC = $(CMOCK_DIR)/src UNITY_SRC = $(CMOCK_DIR)/vendor/unity/src MOCKS_DIR = mocks TARGET = my_try # mock file NAME_DEP = my_math H_DEP = $(NAME_DEP).h C_MOCKS = $(MOCKS_DIR)/Mock$(NAME_DEP).c # UT code C_UT = $(TARGET)_ut.c C_RUN = $(TARGET)_runner.c C_SOURCES = $(UNITY_SRC)/unity.c $(CMOCK_SRC)/cmock.c C_SOURCES += my_try.c C_SOURCES += $(C_MOCKS) $(C_UT) $(C_RUN) C_INCLUDE = -I$(CMOCK_SRC) -I$(UNITY_SRC) -I$(MOCKS_DIR) -I. C_OBJECTS = $(C_SOURCES:.c=.o) all: $(TARGET) $(TARGET): $(C_OBJECTS) $(CC) $(CFLAGS) $^ -o $@ %.o:%.c $(CC) $(CFLAGS) $(C_INCLUDE) -o $@ -c $< clean: rm -rf $(MOCKS_DIR) rm -f $(TARGET) $(C_RUN) $(C_OBJECTS) mock: mkdir -p $(MOCKS_DIR) ruby ../cmock/lib/cmock.rb $(H_DEP) ruby ../cmock/vendor/unity/auto/generate_test_runner.rb $(C_UT) $(C_RUN) run: ./$(TARGET)
$ make run ./my_try my_try_ut.c:17:test_add:FAIL: Expected 3 Was 2 my_try_ut.c:20:test_sub:PASS ----------------------- 2 Tests 1 Failures 0 Ignored FAIL
总结:
通过cmock,我们可以屏蔽到一些外部接口,而把注意力集中在自身的代码上,这点还挺好用的。
上面的例子因为很简单的,所以用起来一点不费劲,但放到实际项目中,操作起来估计就没这么easy了。
以后,有机会在实际项目试一下。