単体テスト環境を作ってみる
http://qiita.com/tksmiura/items/f783cab446a4a1075bba
の続き
- とりあえずgcovを使う
- 'make gcov'と打つだけでカバレッジが取れるようにしたい。
##実装結果
all: main
#TARGETS
PROGRAM = main
SRCS = main.c
TEST = ut_main
TEST_SRCS = ut_main.c
GCOV_TEST = ut_main_gcov
# ENVIRONMENT
CC ?= gcc
CFLAGS ?= -Wall -O2
# suffixes
.SUFFIXES: .c .o .go
# target
$(PROGRAM): $(SRCS:.c=.o)
$(CC) -o $(PROGRAM) $^
# サフィックスルール
.c.o:
$(CC) $(CFLAGS) -c $<
.c.go:
$(CC) $(CFLAGS) --coverage -o $@ -c $<
# ファイル削除用ターゲット
.PHONY: clean
clean:
$(RM) $(PROGRAM) $(SRCS:.c=.o) $(TEST) $(TEST_SRCS:.c=.o) $(GCOV_TEST) *.gcda *.gcno *.gcov *.go
.PHONY: test
test: $(TEST)
./$(TEST)
$(TEST): $(TEST_SRCS:.c=.o)
$(CC) -o $(TEST) $^
.PHONY: gcov
gcov: $(GCOV_TEST)
./$(GCOV_TEST)
gcov -b $(TEST_SRCS:.c=.gcda)
$(GCOV_TEST): $(TEST_SRCS:.c=.go)
$(CC) $(CFLAGS) --coverage -o $(GCOV_TEST) $^
main.c
#include <stdio.h>
static int func1(int parm)
{
if (parm >= 0)
return 1;
return 0;
}
int main(int argc, char *argv[])
{
printf("Hello World!\n");
printf("arg test %d\n", func1(argc));
return 0;
}
ut_main.c
#include <stdio.h>
#include <dlfcn.h>
#include <stdbool.h>
/* test function prototype */
typedef bool (*Test)(void);
#define main __original_main
#include "main.c"
#undef main
#define UT_ASSERT(f) {if (!(f)) {printf("%s:%u: '%s' is NG\n", __FILE__,__LINE__,#f);return false;}}
bool test001(void)
{
UT_ASSERT(func1(1) == 1);
return true;
}
bool test002(void)
{
UT_ASSERT(func1(0) == 1);
return true;
}
bool test003(void)
{
UT_ASSERT(func1(-1) == 0);
return true;
}
int main(int argc, char *argv[])
{
Test t;
bool ret;
int i;
char func_name[100];
unsigned int count_ok = 0, count = 0;
for (i = 0; i < 100; i++) {
sprintf(func_name, "test%03d", i);
t = (Test) dlsym(RTLD_DEFAULT, func_name);
if (t != NULL) {
count++;
ret = (*t)();
if (ret)
count_ok++;
else
printf("test NG %s\n", func_name);
}
}
printf("result %u/%u \n", count_ok, count);
}
###実行結果
MAC OS X(10.12.4)
% make gcov
cc -Wall -O2 --coverage -o ut_main.go -c ut_main.c
cc -Wall -O2 --coverage -o ut_main_gcov ut_main.go
./ut_main_gcov
result 3/3
gcov -b ut_main.gcda
File './main.c'
Lines executed:57.14% of 7
Branches executed:100.00% of 2
Taken at least once:100.00% of 2
No calls
./main.c:creating 'main.c.gcov'
File 'ut_main.c'
Lines executed:95.24% of 21
Branches executed:100.00% of 12
Taken at least once:66.67% of 12
No calls
ut_main.c:creating 'ut_main.c.gcov'
技術的な話
- makeで別オプションのビルドをするために、実行ファイル名を変えるのと合わせ、独自の拡張子(*.go)を導入、ルールを追加(あっ、go言語と被る?)、リンカはどうせマジックナンバーで見ているので勝手にリンクしてくれるだろう(保証なし)
- make時にgcovを掛けるところまで実行
- テストコードのカバレッジが出てしまうのもイマイチ