单元测试开发指南
本指南旨在帮助开发者为
virt-awaresched项目编写高质量的 C++ 单元测试(Unit Test, UT)。我们将介绍整体测试框架、环境搭建、用例编写规范以及运行与覆盖率分析方法,确保代码质量可控、可维护。
测试框架说明
我们采用 Google Test (GTest) 作为核心单元测试框架,并结合 MockCpp 实现对外部依赖的行为模拟,以支持复杂模块的隔离测试。
技术栈
表 1 工具用途说明
| 工具 | 用途 |
|---|---|
| GoogleTest | C++ 单元测试框架,提供断言、测试套件管理等功能。 |
| MockCpp | 轻量级 C++ Mock 框架,用于接口打桩与行为验证。 |
| CMake | 构建系统,自动化编译与链接测试目标。 |
| Bash Script | 封装构建脚本 (build.sh),简化操作流程。 |
编译构建
单元测试使用cmake进行构建和管理,详细内容在test目录下可以进行查看。
环境准备
单元测试支持以下两种运行方式:
- 方式一:在物理机中直接运行 UT
- 方式二:在预编译容器中运行 UT
方式一:在物理机中运行 UT
开发环境搭建参考《构建指导》。
推荐在
openEuler Linux (ARM64)下执行项目构建,进入virt-awaresched所在目录。执行以下命令:
shellbash build.sh test
方式二:在预编译容器中运行 UT
使用限制
预编译镜像中已经安装 virt-awaresched 编译构建和 UT 所需的构建工具及系统依赖。构建和 UT 使用同一个 oe2403-v1 容器即可完成。
源码编译和 UT 不需要将宿主机的 /lib/modules 等目录挂载到容器,也不需要授予容器额外的内核权限。
首次构建 UT 时,构建系统会下载 GoogleTest、MockCpp 及 MockCpp ARM64 补丁,需确保容器可以访问 cmake/gtest.cmake 和 cmake/mockcpp.cmake 中配置的下载地址。
拉取镜像并启动容器
该镜像允许匿名拉取,执行:
docker pull swr.cn-north-4.myhuaweicloud.com/ubscore/ubs-virt:oe2403-v1若返回
denied或unauthorized,请向镜像仓库管理员申请读取权限后重试。
启动容器:
docker run -it \
--name=ubs-virt \
swr.cn-north-4.myhuaweicloud.com/ubscore/ubs-virt:oe2403-v1 \
/bin/bash在容器中运行 UT
进入容器后,拉取源码并执行:
git clone -b openEuler-24.03-LTS-SP3 \
https://gitcode.com/openeuler/ubs-virt.git \
/home/ubs-virt-src
cd /home/ubs-virt-src/virt-awaresched
bash build.sh testbash build.sh test 会在该容器中完成 UT 的构建并运行全部用例,无需额外执行依赖安装步骤,也无需为 UT 另行创建容器。
结果判断
脚本退出码为0,且日志汇总输出PASSED(无FAILED用例),表示UT全部通过,示例如下:
[==========] 184 tests from 18 test suites ran.
[ PASSED ] 184 tests.若运行指定用例,可通过--gtest_filter过滤,用法见下文"增加单元测试用例"。
增加单元测试用例
场景一:向已有测试文件补充用例
背景设定
开发者想针对当前的业务代码
src/vasd/cluster_sched/cluster_sched.cpp中的UpdateDomainInfo函数添加测试用例,当前在test/vasd/cluster_sched/test_cluster_sched.cpp已经存在部分用例。
新增测试代码
在test/vasd/cluster_sched/test_cluster_sched.cpp中新增如下代码:
TEST_F(TestClusterSched, testUpdateDomainInfo1)
{
MOCKER_CPP(&LibvirtHelper::GetVmInfoList, VasRet(LibvirtHelper::*)(VmInfoMap &))
.stubs()
.will(invoke(GetVmInfoListMockSuccess));
MOCKER(&ClusterSched::SelectVmNuma).stubs().will(returnValue(VAS_OK));
MOCKER(&ClusterSched::Alloc).stubs().will(returnValue(VAS_ERROR)).then(returnValue(VAS_OK));
MOCKER(&ClusterSched::Assign).stubs().will(returnValue(VAS_ERROR)).then(returnValue(VAS_OK));
std::string domainKey = uuid01 + "_0";
EXPECT_EQ(ClusterSched::GetInstance().UpdateDomainInfosAndSched(), VAS_OK);
EXPECT_FALSE(ClusterSched::GetInstance().domainMap_[domainKey].isReScheded);
EXPECT_EQ(ClusterSched::GetInstance().UpdateDomainInfosAndSched(), VAS_OK);
EXPECT_FALSE(ClusterSched::GetInstance().domainMap_[domainKey].isReScheded);
EXPECT_EQ(ClusterSched::GetInstance().UpdateDomainInfosAndSched(), VAS_OK);
EXPECT_TRUE(ClusterSched::GetInstance().domainMap_[domainKey].isReScheded);
}验证用例
在virt-aware目录下对用例进行用例验证。
执行以下命令:
bash build.sh test -- --gtest_filter="TestClusterSched.testUpdateDomainInfo1"其中,TestClusterSched为**TestSuite名,testUpdateDomainInfo1为TestName**。
场景二:为新业务模块创建全新单元测试
背景设定
开发者在当前项目基础上,增加了新的业务功能,希望对新的业务代码编写对应的单元测试。以本项目的
api模块为例,开发者完成了api模块,代码位于src/vasd/api,目前需要进行单元测试。
查找模块名
查看src/vasd/api下日志模块的CMakeLists库名为api。
增加模块UT目录
在 test/vasd目录下新建 api目录,并创建CMakeLists.txt文件,在CMakeLists.txt文件中加入如下内容:
add_ut(ubse_log)在 test目录下CMakeLists.txt文件中添加如下内容:

开发UT代码
在test/api目录下新建测试文件test_api.h和test_api.cpp,完成对具体的业务代码的测试,在TestApi测试套中写了一个测试用例. 详细测试代码, 请参考test/vasd/api/。
运行模块的UT代码
在virt-awaresched目录下, 运行bash build.sh test -- --gtest_filter="TestApi.*"查看用例运行情况。
遵循 木兰宽松许可证第2版(MulanPSL2)