UT 目录结构
当前单元测试位于 UBSocket 下的 unit_test 的目录中,遵循着
.
├── CMakeLists.txt
├── brpc
│ ├── CMakeLists.txt
│ └── brpc_iobuf_adapter_test.cpp
└── urpc_util_test.cpp
这样的目录结构,其中一级目录下的 urpc_util_test.cpp 说明它是 ubsocket 中 urpc_util.c 的单元测试。brpc 目录下的则是针对 ubsocket-brpc_adapter 单独的单元测试目录。
添加单元测试
如果想为 ubsocket 通用功能写测试用例,那么需要在 unit_test/ 目录下创建一个 foo_test.cpp 文件,一般它的开头处类似这样:
#include "foo.h" # 对应功能的头文件
#include <gtest/gtest.h>
#include <mockcpp/mockcpp.hpp>
class FooTest : public testing::Test {
public:
void SetUp() override
{
}
void TearDown() override
{
GlobalMockObject::verify(); // 在每次 testcase 结束后,将 mockcpp 修改的代码段复原
}
}
TEST_F(FooTest, CaseName) // 测试功能的名字
{
// 参考 https://google.github.io/googletest/primer.html
EXPECT_TRUE(true);
}
说明: 单元测试主要使用 gtest 框架,mock 功能源自 mockcpp. 因为 mockcpp 可以直接 mock glibc 提供的 syscall > wrapper,如 read、write 等,而 gtest 附带的 gmock 则需要用户提供一个接口。
在编写完单元测试之后,在 unit_test/CMakeLists.txt 中的 target_source 项将 foo_test.cpp 添加。最终效果如
target_source(ubsocket_test
PRIVATE
urpc_util_test.cpp
+ foo_test.cpp
)
编译、运行、查看覆盖率
cd ubs-comm/src/ubsocket
# 编译 ubsocket 与单元测试,注意 -DUBSOCKET_BUILD_TEST=ON 和 -DUMQ_BUF_LIB=...
# 启用覆盖率可以通过 -DUBSOCKET_ENABLE_COVERAGE=ON
# 如果想观察下载进度 -DFETCHCONTENT_QUIET=OFF
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DUBSOCKET_BUILD_TESTS=ON \
-DUBSOCKET_ENABLE_COVERAGE=ON \
-DUMQ_INCLUDE=/path/to/umq -DUMQ_LIB=/path/to/libumq -DUMQ_BUF_LIB=/path/to/libumq_buf \
-DOPENSSL_ROOT_DIR=/path/to/openssl
cmake --build build -j32
# 运行单元测试
ctest --test-dir build --output-on-failure
# 如果只想运行 brpc adapter 相关的单元测试
ctest --test-dir build --output-on-failure -R brpc
# 查看覆盖率
# 覆盖率 html 在 build/coverage_report/index.html
# 原始 lcov 覆盖率文件在 build/coverage_filtered.info
cmake --build build --target coverage
默认情况下它会下载、编译 gtest/mockcpp.
如果想使用系统自带的 gtest,可以在编译时指定 -DUBSOCKET_USE_SYSTEM_GTEST=ON 不过系统自带的版本可能与 mockcpp 不兼容,会在 gtest 中出现 delete self 时的 segfault.
另外,
特别需要注意: 一定要确保 -DUMQ_BUF_LIB=...
文件存在、有效,否则最终链接时可能会出现符号找不到的问题。如果不显示指定,它的默认值为 /usr/lib64/libumq_buf.so.
[ 99%] Linking CXX executable ../../brpc_adapter_test
[100%] Linking CXX executable ../ubsocket_test
/usr/bin/ld: /home/chenzhiwei/ubsocket/src/hcom/umq/build/src/libumq.so.0.0.1: undefined reference to `umq_huge_qbuf_headroom_reset'
/usr/bin/ld: /home/chenzhiwei/ubsocket/src/hcom/umq/build/src/libumq.so.0.0.1: undefined reference to `umq_huge_qbuf_get_type_by_size'
collect2: error: ld returned 1 exit status
make[2]: *** [unit_test/brpc/CMakeFiles/brpc_adapter_test.dir/build.make:105: brpc_adapter_test] Error 1
make[1]: *** [CMakeFiles/Makefile2:1289: unit_test/brpc/CMakeFiles/brpc_adapter_test.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
/usr/bin/ld: /home/chenzhiwei/ubsocket/src/hcom/umq/build/src/libumq.so.0.0.1: undefined reference to `umq_huge_qbuf_headroom_reset'
/usr/bin/ld: /home/chenzhiwei/ubsocket/src/hcom/umq/build/src/libumq.so.0.0.1: undefined reference to `umq_huge_qbuf_get_type_by_size'
collect2: error: ld returned 1 exit status
因为最终是要链接成一个可执行二进制,而 ubsocket 中有使用 umq 相关 API,必须要找到所有符号的定义。在编译
librpc_brpc_adapter.so 时只链接了 libumq.so, 而上面这两个符号均出自 libumq_buf.so,所以需要额外提供
-DUMQ_BUF_LIB=/path/to/libumq_buf 项。
之所以在编译 librpc_brpc_adapter.so 时仅有 libumq.so 依赖却未出现链接错误,是因为动态链接库的符号决议是在运行时做的.
librpc_brpc_adapter.so 依赖 libumq.so,libumq.so 又依赖 libumq_buf.so, 而在运行时可以通过
export LD_LIBRARY_PATH= 能够让 libumq.so 找到 libumq_buf.so,又或者系统路径下存在 libumq_buf.so,如
/usr/lib64/libumq_buf.so 文件存在。