couttast 是一个简单、轻量的 C++ 单元测试库及框架。可用于快速构建基于命令行的可 执行测试程序,却也不仅限于单元测试。详细文档见 wiki。
- 核心功能仅在单个头文件中:tinytast.hpp 可当 header-only 库使用。
- 用统一的
COUT宏打印表达式的值或比较预期结果,提供语句级测试判断; - 用
DEF_TAST宏定义单元测试用例,其函数体可简单等效一个void()函数的写法; - 在
main()入口函数中仅需调用RUN_TAST宏,自动执行测试用例,并返回失败用例数; - 空命令行参数时顺序执行所有用例,否则按每个参数执行匹配的测试用例;
- 命令行参数支持
--list查看已定义的测试用例,--cout可控制输出信息的冗余度。 - 其他
*.hpp文件扩展 header-only 库的测试功能。
- 用统一的
- 高级扩展功能另外打包在静态库中:libcouttast.a 。
- 提供一个
main()函数,但是弱符号,仍支持用户自定义main()函数; - 提供终端颜色打印功能,进一步增加输出信息的可读性;
- 增强命令行参数筛选测试用例的功能,支持简单通配符;
- 支持命令行参数到
ini配置文件的映射,自动读取与程序同名的ini配置文件; - 对于大量测试用例支持多进程模式并行运行测试用例,增加测试效率;
- 其他利于设计单元测试程序的辅助工具库。
- 提供一个
- 依赖低,只依赖 C++ 标准库,核心头文件
tinytast.hpp甚至无需 C++11 功能。 - 利用
couttast书写单元测试用例程序简单、直接、方便。
适用场合:
- 快速验证与测试自己开发的代码功能,并逐步完善为可自动化回归的单元测试,促进可测试 与可维护的代码编写。
- 以测代学,辅助快速编写简易代码块学习、研究不断进化的 C++ 新标准及未熟悉的隐晦特性。
- 测试想集成使用的第三方库,验证满足自己需求的适合的调用方式。
作者目前主要在 Linux 系统下使用验证,当然 header-only 的 C++ 源码是可移植的。
只需在测试文件中包含 tinytast.hpp 头文件,然后用 DEF_TAST 定义一系列类似
void() 函数的代码块,其中可用 COUT 输出或比较感兴趣的值,最后在 main()
函数中调用 RUN_TAST 。
#include "tinytast.hpp"
DEF_TAST(test_name, "测试用例说明")
{
COUT(sizeof(int));
COUT(sizeof(int), 4);
COUT(sizeof(int)==4, true);
}
int main(int argc, char** argv)
{
return RUN_TAST(argc, argv);
}编译、运行大约有如下输出:其中 COUT 单参数时只输出结果,双参数时比较结果并给
出正确或通过与否的判据,然后有额外统计汇总信息。
## run test_name()
|| sizeof(int) =~? 4
|| sizeof(int) =~? 4 [OK]
|| sizeof(int)==4 =~? ture [OK]
<< [PASS] 0 test_name within 81 us
## Summary
<< [PASS] 1
<< [FAIL] 0
可以由多个测试 *.cpp 源文件编译链接在一起,当然只能有一个 main() 定义。
如上只用 header-only 库时编译命令大致如下:
g++ *.cpp -o utMyProgram
# 可能需要用 -I 指定头文件路径如果链接扩展静态库编译测试程序,则可省略写 main() 函数,只专注写各个测试用例。
编译命令大致如下:
g++ *.cpp -lcouttast -o utMyProgram
# 可能需要用 -I 指定头文件存放目录,及 -L 指定静态库存放目录当然在正式项目中建议用专门的构建工具,避免手写编译命令。如果按下节构建方式安装
时,头文件可能被安装至 /usr/local/include/couttast/ ,则在使用时建议包含子目
录,如下写法:
#include "couttast/couttast.h"
/* 或简单头文件 */
#include "couttast/tinytast.hpp"只用 tinytast.hpp 及其他一些 *.hpp 头文件的话,其实不需要特别地构建。
本仓库也提供了几个静态库封装、单元测试及一些可运行示例,需要编译构建。
make
make example
# make test按本仓库主目录上提供的 makefile ,直接 make 会生成如下几个目录:
obj/: 编译过程的中间目标文件;lib/: 生成的静态库,其中libtinytast.a只有一个main()函数,libcouttast包含所有扩展功能;bin/: 生成的可执行程序,包含可执行的单元测试程序。- 可执行的示例程序,生成在
example/的各个子目录下。
可选使用 make test 运行单元测试,用这个单元测试框架本身测试其主要功能。
可用 make test -n 查看如何手动运行单元测试程序。
也提供了 cmake 构建系统,可用如下标准的构建与安装命令:
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME
make
# make test
# make install用 cmake 工具时,按惯例构建工作在单独的 build/ 子目录下进行。最后一步安装
至个人 $HOME 下的几个子目录,include/couttast 、lib/ 与 bin/ ,这是为
了避免 /usr/local 的写权限限制。
如果在前面步骤 cmake .. 时不加 CMAKE_INSTALL_PREFIX 选项参数,则默认安装至
系统目录 /usr/local 。安装至系统目录后,在写实际的单元测试程序时可直接使用,
或集成至其他 CMake 构建的项目。如果安装在 $HOME 目录或其他目录,则可能需要在
构建单元测试程序时调整相应的编译参数。
有三种方法构建可执行测试程序(命令行程序),可参见 example/basiccpp-* 的几个子目录。
- 自己写
main函数。可以在调用RUN_TAST之前作些特殊的预处理。 - 链接静态库
libtinytast.a或libcouttast.a,自己不用写main函数, 只关注写测试用例。libtinytast.a的功能相当简单,就只为提供个main入口函数。 链接libcouttast.a库即可使用扩展功能。 - 将自己的测试用例编译为动态链接库,要求导出
tast_main()函数,该函数一般会 最终调用RUN_TAST宏。然后用bin/tast_drive程序驱动编译的测试动态库, 将动态库作为第一个命令行参数,剩余参数会传给内部的测试库。
在 example/ 目录下的 basiccpp-umain/ 子目录演示了第一种构建法,
basiccpp-uliba/ 子目录演示了第二种构建法,basiccpp-udyso/ 演示了第三种构建
法。其中涉及的单元测试用例,都引用 basiccpp/ 子目录的源文件,所以是相同的单
元测试用例用不同的方法构建测试程序。注意这套单元测试用例有意设置几个失败,以演
示失败时的输出样式,且其中涉及许多 sizeof 运算符,在不同系统上编译运行可能有
不同的结果。
按第三种方法,驱动单元测试动态链接库的使用方式如下:
bin/tast_drive libmytast.so --list
bin/tast_drive libmytast.so [test_name_fileter]注意加载动态库可能要导出环境变量 $LD_LIBRARY_PATH,毕竟一般不会将测试动态库
放到系统路径中。不过若用 cmake 构建时,在 build/ 目录下执行 ./tast_dirve
可不必添加环境变量 $LD_LIBRARY_PATH ,可直接执行:
./tast_drive example/libtast-basiccpp.so
example/tast-basiccpp-uliba.exe
example/tast-basiccpp-umain.exe这些构建出来的单元测试程序支持的一些命令行参数,详见后文。
此外,因为动态链接库的方式比较复杂,也更多陷阱,在没特殊需求时,建议使用前两种 方法构建独立可运行的单元测试程序。
在 libcouttast.a 中定义的 main() 入口函数大致如下:
#define WEAK_SYMBOL __attribute__((weak))
int WEAK_SYMBOL main(int argc, char* argv[])
{
return tast::main(argc, argv);
}这意味自己的测试程序在链接 libcouttast.a 的同时,如果有需要仍可定义自己的
main() 函数,覆盖默认提供的 main() 函数。比如在调用 tast::main() 之前先
做些其他预处理工作。
另外,基础库 libtinytast.a 中仅有的 main() 函数也是弱符号,也可以被覆盖。
只不过既然自己写了 main() 函数,就没必要再链接 libtinytast.a 了,它没有包
含其他许多花哨的扩展功能。
开源库,例行欢迎 issue fork pr ,如果觉得此 couttast 库对您有用的话。
建议使用 cmake 构建,在 build/ 目录下执行 cmake .. && make 后,请执行
make test 确保测试通过。主要是 utCoutTast 要通过,它从 utest/ 子目录的源
文件构建,但在运行时需要读一些测试数据也在 utest/ 目录下,所以想手动执行它时
要先切换到该目录,然后如下运行:
cd utest
../build/utCoutTast [--help | --list | 用例名参数]或者在 build/ 目录直接指定 --cwd 选项执行:
./utCoutTast --cwd=../utest- 优化测试用例底层管理,从
map改为vector紧凑存储,且避免复制字符串字面 量的用例名与文件名。 - 增加对测试单元与测试套件对相关测试用例的组织方案,利于管理大量测试用例。
- 优化头文件组织,划分为三级功能层次。
- 增加对调用外部系列命令的测试功能。
- 增加以数据配置化单元测试的功能。
- 其他增强单元测试及命令行程序的功能。
- 增加扩展静态库
libcouttast.a,主要是终端颜色打印、用例筛选增强、自动读取 ini 配置、多进程并行等功能; - 原来的只含
main()函数的库由libtast_main.a改名为libtinytast.a; - 单元测试管理类的全局单例宏名由
_TASTMGR改为G_TASTMGR; - 为
COUT宏增加一系列COUT_BIT_*常量控制各类信息的输出,由此Print()方法需要额外的标志参数。 - 移除对
TAST简单宏及TAST_RESULT的定义。
核心文件:tinytast.hpp 。
单头文件简易版。增加了 DEF_TAST 宏定义测试用例,在 main() 入口函数只需用
RUN_TAST 自动调用所有被定义的测试用例。可用命令参数指定筛选运行部分测试用例,
并安排测试顺序。内部采用一个全局单例对象管理所有测试用例,每个 DEF_TAST 的用
例除了名称与可选描叙外,函数体可按普通 void 函数编写,用 COUT 宏比较结果。
提供一些应用示例,及简单驱动程序或封装库,支持 make 与 cmake 构建。
核心文件:tast_util.hpp 。
极简速成版。除了 COUT 比较观察宏外,只定义了 TAST 宏调用普通 void 函数,
用 TAST_RESULT 宏汇报结果。没有专门语法定义测试用例,需在 main() 函数中手
动调用作为用例的 void 函数或用 TAST 宏封装调用。