
测试开发工具【免费下载链接】doctestThe fastest feature-rich C11/14/17/20/23 single-header testing framework项目地址https://gitcode.com/gh_mirrors/do/doctest点击查看免费下载doctest是一款 C11/14/17/20/23 单头文件测试框架即使完全不传任何命令行参数也能开箱即用地运行测试。但当测试规模增长、需要接入 CI、或要把测试框架嵌入生产代码时本文整理的这套命令行体系——查询型参数Query flags、字符串/整型选项、布尔选项、通配符过滤器以及--dt-前缀互操作机制——就是精确控制测试行为的核心工具。读完本文你将掌握 doctest 全部命令行参数的语义、默认值与源码实现并学会在自定义main()中用代码覆盖参数以及如何与既有程序的命令行解析和平共处。命令行参数总体设计doctest 的命令行参数分为三大类理解它们的语法差异是正确使用的第一步查询型参数Query flags打印结果后程序直接退出不执行任何测试用例。若框架被集成进由客户端代码提供main()的程序见 doc/markdown/main.md程序应在调用doctest::Context的run()之后检查shouldExit()的返回值并自行退出——是否退出由用户决定。整型/字符串选项Int/String options必须在之后跟一个值且等号两侧不能有空格例如--order-byrand。布尔选项Bool options之后可跟1/yes/on/true或0/no/off/false也可以像普通 flag 一样直接省略value部分此时默认视为true。在 doctest/parts/private/context.cpp 的parseArgs()中可以看到这种先解析布尔值、再回退为纯 flag的实现逻辑先尝试用parseIntOption()匹配--选项值形式若匹配失败再尝试用parseFlag()匹配裸 flag命中即置为true若两者都未命中且处于带默认值模式则使用代码内默认值。真正的值解析由parseOptionImpl()完成它从参数列表末尾向前扫描、取最后一个匹配项并校验选项前的字符全部是-避免误伤普通命令行参数。查询型参数Query flags查询参数说明-?--help-h打印帮助信息列出全部参数与选项-v--version打印 doctest 框架版本号-c--count打印与当前过滤器匹配的测试用例数量-ltc--list-test-cases按名称列出所有与当前过滤器匹配的测试用例-lts--list-test-suites列出所有至少有一个测试用例匹配当前过滤器的测试套件-lr--list-reporters列出所有已注册的 reporters从源码看所有查询参数在命中后都会额外设置p-exit true见 doctest/parts/private/context.cpp这正是shouldExit()返回true的依据。Context::run()中还会在进入测试循环前专门处理help、version、list_reporters与no_run分支它们只向 reporters 广播report_query事件后便直接返回绝不再执行任何测试用例。整型/字符串选项选项说明-tc--test-casefilters按测试用例名称过滤。默认所有测试用例都匹配若传入如--test-case*math*,*sound*则只有至少命中逗号分隔列表中一个通配符模式的测试用例才会被执行/计数/列出-tce--test-case-excludefilters与--test-casefilters相反逗号分隔列表中任一模式命中即跳过该测试用例-sf--source-filefilters同--test-casefilters但按测试用例所在源文件过滤-sfe--source-file-excludefilters同--test-case-excludefilters但按测试用例所在源文件过滤-ts--test-suitefilters同--test-casefilters但按测试套件过滤-tse--test-suite-excludefilters同--test-case-excludefilters但按测试套件过滤-sc--subcasefilters同--test-casefilters但按子用例subcase名称过滤。它不会过滤测试用例本身测试用例必须执行才能发现子用例所以建议与--test-casefilters搭配使用。注意该选项不会运行选中子用例内部的嵌套子用例-sce--subcase-excludefilters同--test-case-excludefilters但按子用例名称过滤-r--reportersfilters要使用的 reporters 列表默认为console。可用逗号同时指定多个如--reportersxml,junit执行顺序按注册优先级数值越小越靠前-o--outstring输出文件名。源码显示若指定的文件无法打开会向std::cerr报错并回退到std::coutdoctest/parts/private/context.cpp-ob--order-bystring执行前对测试用例排序可选值file按所在文件/suite按测试套件/name按名称/rand随机/none不排序。默认file。注意file、suite、name三种排序结果与编译器相关可能因编译器不同而不同-rs--rand-seedint随机排序的种子-f--firstint通过当前过滤器的第一个要执行的测试用例——用于范围化执行见 examples/range_based_execution.py-l--lastint通过当前过滤器的最后一个要执行的测试用例——用于范围化执行-aa--abort-afterint累计失败断言数达到该值后停止执行测试用例/断言。默认 0 表示不停止。注意框架用一个异常来终止当前测试用例且与断言的级别CHECK/REQUIRE无关——所以请小心析构函数中的断言……-scfl--subcase-filter-levelsint只对嵌套子用例的前int层应用子用例过滤器更深层的子用例直接运行。默认值极大相当于过滤任何子用例关于这些选项的默认值源码doctest/parts/private/context.cpp给出了权威依据out默认、order-by默认file、rand-seed默认0、first默认0、last默认UINT_MAX、abort-after默认0、subcase-filter-levels默认INT_MAX。排序的具体实现在Context::run()中file走fileOrderComparator比较文件路径、行号与模板 idsuite走suiteOrderComparator先套件后文件行号name走nameOrderComparator先名称后套件rand则用std::srand(p-rand_seed)后执行一次随机洗牌none保持注册顺序——这对死亡测试这类针对特定用例反复启动进程的场景尤其有价值可以省去每次启动的排序开销。布尔选项选项说明-s--successbool在输出中包含成功断言的详情-cs--case-sensitivebool过滤器是否区分大小写默认不区分-e--exitbool测试结束后退出程序。仅当客户端提供了main()入口时才有意义——程序应在调用run()后检查shouldExit()并退出以便只跑测试、不继续业务逻辑-d--durationbool打印每个测试用例耗时秒-m--minimalbool只打印失败的测试-q--quietbool不打印任何输出。源码中该选项会让输出流指向一个DiscardOStreamdoctest/parts/private/context.cpp-nt--no-throwbool跳过与异常相关的 断言 检查-ne--no-exitcodebool即使测试失败也总是返回成功退出码-nr--no-runbool跳过所有运行时 doctest 操作但注册测试的代码发生在进入main()之前不会受影响。当框架集成进提供了main()的客户端代码、用户只想运行业务程序时非常有用-ni--no-introbool输出中省略框架 intro-nv--no-versionbool输出中省略框架版本号-nc--no-colorsbool禁用输出中的颜色-fc--force-colorsbool即使检测不到 tty 也强制使用颜色-nb--no-breaksbool断言失败时禁止在调试器中打断点-ns--no-skipbool不跳过用装饰器标记为 skip 的测试用例源码中对应tc.m_skip !p-no_skip的判断doctest/parts/private/context.cpp-gfl--gnu-file-linebool输出中的行号分隔符用:n:还是(n):gnu 模式通常供 Linux 工具/IDE 使用用:分隔。源码显示其默认值为!DOCTEST_MSVC即非 MSVC 平台默认开启 gnu 风格-npf--no-path-filenamesbool打印文件名时去掉路径——希望不同环境得到相同输出时很有用-sfp--strip-file-prefixesstring从输出中的任何文件路径里移除前缀列表中最长匹配的那个前缀与-npf类似但通过保留部分相对路径来保留上下文。试一下--sfp${CMAKE_SOURCE_DIR}/:${CMAKE_BINARY_DIR}/。前缀列表的分隔字符见 doc/markdown/configuration.md#doctest_config_options_file_prefix_separator-nln--no-line-numbersbool输出源位置时行号一律替换为0——当测试位置在源文件内变化时仍能得到一致输出-ndo--no-debug-outputbool禁用附加调试器时输出到调试控制台除了表格中的内容源码还暴露了两个未出现在旧版表格中的布尔开关--no-skipped-summarynss关闭被跳过用例的汇总与--no-time-in-outputntio输出中不含时间它们在较新版本中同样可用。过滤器通配符与转义规则过滤器是一组逗号分隔的通配符模式*表示匹配任意序列?表示匹配任意单个字符。带空格的模式需要用双引号包裹例如--test-case*no sound*,vaguely named test number ?包含逗号或反斜杠的模式可以用\转义例如--test-casethis\,test\,has\,commas\,and\,a\\\,backslash\,followed\,by\,a\,comma如果反斜杠后面既不是\也不是,则按原样保留例如--test-caseTest that \ works correctly注意你的 shell 本身也可能用\做转义因此\可能先被 shell 消费掉而不是传给 doctest。从实现层面看doctest/parts/private/context.cpp 的parseCommaSepArgs()完整实现了这套转义规则它逐字符扫描遇到\后仅当下一字符是,或\时才输出该字符本身转义否则保留反斜杠遇到未转义的,则切分出一个 filter 条目。过滤的最终应用则发生在Context::run()中对每个测试用例依次核对 8 组过滤器源文件包含/排除、套件包含/排除、名称包含/排除、子用例包含/排除任何一组不匹配都会skip_me true。源码里过滤器的存储布局是 9 个槽位的数组p-filters[0..8]其中filters[8]存放 reporters 列表。前缀机制--dt-与客户端命令行互操作所有参数都有一个带前缀的版本默认前缀为--dt-。例如--version也可以写作--dt-version或--dt-v。默认前缀可以通过定义DOCTEST_CONFIG_OPTIONS_PREFIX修改见 doc/markdown/configuration.md#doctest_config_options_prefix。同时所有无前缀版本可以通过定义DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS整体禁用见 doc/markdown/configuration.md#doctest_config_no_unprefixed_options。这套设计的目的是让框架被集成进客户端代码库时能轻松与其他命令行参数解析共存所有 doctest 相关参数都可加上前缀以避免冲突用户也能从自己的参数解析中排除一切以--dt-开头的参数。源码中parseOption()在DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS未定义时会先用pattern strlen(DOCTEST_CONFIG_OPTIONS_PREFIX)构造去掉前缀的短模式去匹配一遍即无前缀形式再匹配完整带前缀模式定义该宏后则只匹配带前缀的形式。用dt_removed辅助类过滤客户端参数如果客户端没有排除--dt-前缀参数的现成机制可以用框架提供的dt_removed辅助类把它们过滤掉#define DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS #define DOCTEST_CONFIG_IMPLEMENT #include doctest.h class dt_removed { std::vectorconst char * vec; public: dt_removed(const char **argv_in) { for (; *argv_in; argv_in) if (strncmp(*argv_in, --dt-, strlen(--dt-)) ! 0) vec.push_back(*argv_in); vec.push_back(NULL); } int argc() { return static_castint(vec.size()) - 1; } const char **argv() { return vec[0]; } // Note: non-const char **: }; int program(int argc, const char **argv); int main(int argc, const char **argv) { doctest::Context context(argc, argv); int test_result context.run(); // run queries, or run tests unless --no-run if (context.shouldExit()) // honor query flags and --exit return test_result; dt_removed args(argv); int app_result program(args.argc(), args.argv()); return test_result app_result; // combine the 2 results } int program(int argc, const char **argv) { printf(Program: %d arguments received:\n, argc - 1); while (*argv) printf(%s\n, *argv); return EXIT_SUCCESS; }当程序这样运行时program.exe --dt-test-casemath* --my-option -s --dt-no-breaks输出为Program: 2 arguments received: --my-option -s可以看到--dt-test-casemath*与--dt-no-breaks已被 doctest 消费并从传给客户端program()的参数中剔除而-s由于被DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS禁用无前缀形式后不再被 doctest 解析原样交给了客户端程序——这正是该示例演示无前缀选项被禁用后交由客户端处理的精妙之处。在代码中设置选项Context API 的 defaults/overrides所有命令行选项都可以在代码中设置默认值或覆盖值——前提是你自己提供main()详见 doc/markdown/main.md。注意查询 flag 无法用代码设置过滤器只能通过addFilter()追加、或通过clearFilters()全部清空用户无法用代码单独移除某个过滤器。#define DOCTEST_CONFIG_IMPLEMENT #include doctest.h int main(int argc, char **argv) { doctest::Context context; // !!! THIS IS JUST AN EXAMPLE SHOWING HOW DEFAULTS/OVERRIDES ARE SET !!! // defaults context.addFilter(test-case-exclude, *math*); // exclude test cases with math in their name context.setOption(abort-after, 5); // stop test execution after 5 failed assertions context.setOption(order-by, name); // sort the test cases by their name context.applyCommandLine(argc, argv); // overrides context.setOption(no-breaks, true); // dont break in the debugger when assertions fail int res context.run(); // run if (context.shouldExit()) // important - query flags (and --exit) rely on the user doing this return res; // propagate the result of the tests int client_stuff_return_code 0; // your program - if the testing framework is integrated in your production code return res client_stuff_return_code; // the result from doctest is propagated here as well }务必调用context.shouldExit()——当使用了查询 flag或--no-run置为true时它会被置位由用户负责以正常方式退出程序。从源码看Context构造函数与applyCommandLine()都会调用parseArgs()前者额外传入withDefaultstrue而setOption()的实现是构造- option value形式的参数串再走一遍解析doctest/parts/private/context.cpp所以先applyCommandLine再setOption的调用顺序天然形成命令行优先、代码后覆盖的语义若想在命令行之前设定默认值则在applyCommandLine()之前调用即可。实战场景范围化执行range-based execution--firstint与--lastint组合可以只执行通过当前过滤器后落入某个序号区间内的测试用例这是把一个大测试集切分到多台机器或多个进程并行执行的利器。仓库附带的 examples/range_based_execution.py 演示了完整流程先用--dt-count1查询通过过滤器的未跳过用例总数解析输出行[doctest] unskipped test cases passing the current filters:按 CPU 核心数把[1, N]的序号区间均分例如 8 核跑 100 个用例时切分为([1, 13], [14, 26], [27, 39], [40, 52], [53, 65], [66, 78], [79, 91], [92, 100])每个 worker 用--dt-firstfirst --dt-lastlast启动一个测试进程实例通过multiprocessing.Pool并行执行。该脚本配合--dt-前缀使用说明范围化执行通常与前缀机制一起出现在需要脚本化、CI 化的场景中。仓库的测试输出样例如 examples/all_features/test_output/count.txt也印证了--count的输出格式可作为对照基准。与 reporters 的联动--reportersfilters与-r是唯一以过滤器形式出现的运行时选项选择结果决定了输出格式默认console另有流式streaming的xml和缓冲式buffering的junit可用多个 reporter 用逗号分隔。所有已注册的 reporter/listener 可用--list-reporters查看自定义 reporter 通过REGISTER_REPORTER注册后即可在命令行中被选中详见 doc/markdown/reporters.md。输出目标默认是stdout可用--outfilename重定向到文件。在 doctest/parts/private/context.cpp 中可以看到若filters[8]为空则默认塞入console随后遍历所有已注册 reporters用matchesAny()按过滤器匹配选择选中的 reporter 实例在整个运行期间被缓存使用。小结doctest 的命令行体系可以概括为三条主线查询 flag 控制程序要不要跑测试--help/--version/--count/--list-*过滤与排序选项控制跑哪些测试、按什么顺序跑--test-case系列、--source-file系列、--test-suite系列、--subcase系列、--order-by、--first/--last布尔选项控制输出长什么样、失败后怎么处理--success、--minimal、--quiet、--abort-after、--no-*系列。配合--dt-前缀与DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS/DOCTEST_CONFIG_OPTIONS_PREFIX两个配置宏以及在自定义main()中通过Context::addFilter()/setOption()/applyCommandLine()的 defaults/overrides 组合无论是独立测试程序、CI 并行执行还是嵌入生产代码都能获得精确可控、且不与宿主程序参数冲突的测试运行体验。更多相关参考自定义main()与 DLL 场景doc/markdown/main.md前缀与相关配置宏的完整定义doc/markdown/configuration.mdreporter 体系与自定义 reporterdoc/markdown/reporters.md命令行解析核心实现doctest/parts/private/context.cpp范围化执行脚本examples/range_based_execution.py赞分享测试开发工具【免费下载链接】doctestThe fastest feature-rich C11/14/17/20/23 single-header testing framework项目地址https://gitcode.com/gh_mirrors/do/doctest点击查看免费下载相关推荐doctest命令行工具完全指南掌握所有选项和过滤器的使用技巧doctest命令行工具完全指南掌握所有选项和过滤器的使用技巧 doctest 是一个轻量级的C测试框架它不仅编译速度快而且提供了丰富的命令行选项和过测试开发工具Keystone GraphQL 查询过滤器Filters完全指南从标量过滤到关系过滤Keystone GraphQL 查询过滤器Filters完全指南从标量过滤到关系过滤 Keystone 为 Node.js 开发者提供了强大的 Grap后端InfluxDB 3.0 CLI 完全指南从数据库创建到数据查询的命令行操作InfluxDB 3.0 CLI 完全指南从数据库创建到数据查询的命令行操作 你是否还在为时序数据管理工具的复杂操作而困扰是否想快速掌握从数据库创建到数据查数据库时序数据库上一篇深入Easy-PHP揭秘MCL架构如何提升代码可维护性下一篇Agenda任务处理资源控制CPU与内存使用限制创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考