gpt4 book ai didi

从一组单元测试中组成一个组合测试套件程序

转载 作者:太空宇宙 更新时间:2023-11-04 03:36:39 24 4
gpt4 key购买 nike

我正在构建一个 set of modules with unit-tests我想自动生成一个组合程序来执行所有测试。

放纵我内心的控制狂,我决定使用 minunit.h框架并尝试全部手动完成。所以我有两个源文件(还会有更多)。

-rw-r--r-- 1 josh None 6192 Aug 21 23:15 io.c
-rw-r--r-- 1 josh None 2341 Aug 22 00:49 st.c

每个单元都嵌入了一个单元测试(所以我更容易保持更新,而且这次可能真的使用)由 #ifdef TESTMODULE 保护。概述:

... 
//module code
...

#ifdef TESTMODULE
...
//unit tests
...
int main(){
// call unit tests
}
#endif

然后我可以用一个非常短的文件制作一个测试程序。

$ cat > io_test.c
#define TESTMODULE
#include "io.c"
$ make io_test
cc io_test.c -o io_test

我使用相同类型的包含手动编写了一个组合程序,但重新定义了所有全局名称以使其唯一。

# define main io_main 
# define tests_run io_tests_run
# define all_tests io_all_tests
# include "io_test.c"
# undef main
# undef tests_run
# undef all_tests
int io_test(){
printf("running io_test\n");
return io_main();
}

# define main st_main
# define tests_run st_tests_run
# define all_tests st_all_tests
# include "st_test.c"
# undef main
# undef tests_run
# undef all_tests
int st_test(){
printf("running st_test\n");
return st_main();
}

int main(){
return
0 || io_test() || st_test() ;
}

现在我想从更短的 variable 部分列表自动生成它:iost。我可以使用 X-macros 完成大部分工作。

#define HASH #
#define UNITS(_) \
_(io) \
_(st) \
/**/

#define gen_unit_function(unit) \
HASH define main unit##_main \
HASH define tests_run unit##_tests_run \
HASH define all_tests unit##_all_tests \
HASH include STR(unit##_test.c) \
HASH undef main \
HASH undef tests_run \
HASH undef all_tests \
int unit##_test(){ \
printf("running " STR(unit) "_test\n"); \
return unit##_main(); \
}

#define gen_func_call(unit) \
|| unit##_test()

UNITS(gen_unit_function)
int main(){
return
0 UNITS(gen_func_call) ;
}

当然,这永远行不通,因为您无法使用 C 预处理器强制换行。我可以使用什么来解决此限制?

最佳答案

您可以使用 m4 生成源代码,一个更强大的宏处理器。

现在 m4 不会以同样的方式执行 X-macros。您不能简单地传递宏名称并在扩展文本中重新评估它。但是 gnu 文档描述(并分发)了一个具有相同能力的 foreach 宏。

divert(`-1') 
# http://www.gnu.org/savannah-checkouts/gnu/m4/manual/m4-1.4.17/html_node/Foreach.html#Foreach
# foreach(x, (item_1, item_2, ..., item_n), stmt)
# parenthesized list, simple version
define(`foreach', `pushdef(`$1')_foreach($@)popdef(`$1')')
define(`_arg1', `$1')
define(`_foreach', `ifelse(`$2', `()', `',
`define(`$1', _arg1$2)$3`'$0(`$1', (shift$2), `$3')')')

define(`UNITS', (io,st))

divert`'dnl
`#' include <stdio.h>
foreach(`unit', UNITS, `
`#' define main unit`'_main
`#' define tests_run unit`'_tests_run
`#' define all_tests unit`'_all_tests
`#' include "unit`'_test.c"
`#' undef main
`#' undef tests_run
`#' undef all_tests
int unit`'_test(){
printf("running unit`'_test\n");
return unit`'_main();
}
')dnl

int main(){
return
0 foreach(`unit', UNITS, ` || unit`'_test() ') ;
}

然后可以通过运行m4 all_tests.m4 > all_tests.c生成程序。这可以添加到 makefile 中。

all_tests.c:all_tests.m4 *_test.c
m4 $< >$@

但是进入这个 m4 文件来更新列表会很丑陋,所以利用命名约定并使用 make(它知道如何检查文件名和目录等)生成列表 (io,st)。

$cat makefile
testprogs= $(notdir $(wildcard ./*_test.c))
unitprogs= $(subst _test,,$(testprogs))
units= $(basename $(unitprogs))

test:all_tests
./all_tests
all_tests.c:all_tests.m4 makefile $(unitprogs)
m4 -D UNITS="$(units)" $< >$@

既然 make 喜欢用空格分隔的列表,但我们的 m4 文件设置为使用逗号分隔的列表,我们需要在使用前预处理列表,生成这个最终版本。

$cat all_tests.m4
divert(`-1')
# http://www.gnu.org/savannah-checkouts/gnu/m4/manual/m4-1.4.17/html_node/Foreach.html#Foreach
# foreach(x, (item_1, item_2, ..., item_n), stmt)
# parenthesized list, simple version
define(`foreach', `pushdef(`$1')_foreach($@)popdef(`$1')')
define(`_arg1', `$1')
define(`_foreach', `ifelse(`$2', `()', `',
`define(`$1', _arg1$2)$3`'$0(`$1', (shift$2), `$3')')')

define(`UNITS', (patsubst(UNITS,`\W',`,')))

divert`'dnl
`#' include <stdio.h>
foreach(`unit', UNITS, `
`#' define main unit`'_main
`#' define tests_run unit`'_tests_run
`#' define all_tests unit`'_all_tests
`#' include "unit`'_test.c"
`#' undef main
`#' undef tests_run
`#' undef all_tests
int unit`'_test(){
printf("running unit`'_test\n");
return unit`'_main();
}
')dnl

int main(){
return
0 foreach(`unit', UNITS, ` || unit`'_test() ') ;
}

现在,每当一个新模块准备好使用由 TESTMODULE 保护的单元测试 main() 时,就可以通过编写相同的两行代码将其添加到套件中问题中描述的文件,符合模式 *_test.c

#define TESTMODULE 
#include "zz.c"

unit-test 和 all_tests 都将通过 make 简单地编译。

[此 Material 之前发布到comp.lang.c .]

关于从一组单元测试中组成一个组合测试套件程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32163935/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com