OpenHarmony 单元测试补全技能。根据 .d.ts 接口定义,在 ohosTest 的 test 目录下生成完整测试套:以接口文件名为套件名(去掉特殊符号+Test,如 Index.d.ts → IndexdtsTest),包含 beforeAll/beforeEach/afterEach/afterAll,并为每个接口方法生成 4 类边界用例(正常值、最大值、最小值、异常/压力),使用...
根据 .d.ts 接口文件(如 NAPI 生成的 Index.d.ts)在 ohosTest 的 test 文件夹下自动补全单元测试套件,参照 Ability.test.ets 结构,以接口为测试对象,生成符合 Hypium 规范的测试用例。
在 napi_generator 仓库根 或工程目录下执行;脚本均在 src/skills/ohtest/。
| 场景 | 命令示例 | 提示词示例 |
|---|---|---|
| d.ts 生成单测 | python3 src/skills/ohtest/ohtest.py --dts entry/.../Index.d.ts --test-dir entry/src/ohosTest/ets/test |
「根据 Index.d.ts 生成 ohosTest 套件并注册入口」 |
| UITest | python3 src/skills/ohtest/uitest_gen.py --ets entry/src/main/ets/pages/Index.ets ... |
「给 Index.ets 生成 UITest」 |
| 跑 fuzz | python3 src/skills/ohtest/fuzztest.py run -ts GetAppStatsMahFuzzTest -p rk3568 |
「编译并跑这个 fuzz 目标」 |
| 扫 fuzz 套件 | python3 src/skills/ohtest/find_fuzztest.py |
「仓库里有哪些 fuzztest」 |
| ACTS | python3 src/skills/ohtest/actstest.py run <SuiteName> |
「在 out 里跑指定 ACTS suite」 |
| 编静态+动静态对比 | python3 src/skills/ohtest/dyn_static_workflow.py help |
「编 web 静态 HAP 并对比动静态耗时」 |
| 动静态对比 | python3 src/skills/ohtest/compare_dyn_static.py stats|run|compare --src-dir <src> |
「统计 web 动静态可对应用例并对比耗时」 |
| 覆盖率 | python3 src/skills/ohtest/coverage_analysis.py run -t <部件> -p rk3568 |
「拉覆盖率并分析」 |
entry/src/main/cpp/types/libentry/Index.d.ts)、测试目录(如 entry/src/ohosTest/ets/test)、可选模块导入名(如 libentry.so)。*Test.test.ets 文件,并在现有 List.test.ets(或主测试入口)中注册该测试套。Test。例如 Index.d.ts → IndexdtsTest;函数名为 indexdtsTest(),describe 套件名为 IndexdtsTest。Ability.test.ets 一致:export default function <name>Test() {describe('<Name>Test', () => { ... })beforeAll、beforeEach、afterEach、afterAll。it('<method>_tc_N', 0, () => { ... })。对每个 .d.ts 中的导出接口方法,生成 4 个用例:
| 类型 | 说明 | 示例(以 add(a: number, b: number) => number 为例) |
|---|---|---|
| 正常值 | 各种允许的输入类型、典型值 | add(1, 2),expect(result).assertEqual(3) |
| 最大值 | 输入类型的最大值 | add(Number.MAX_SAFE_INTEGER, 0),断言与预期一致 |
| 最小值 | 输入类型的最小值 | add(Number.MIN_SAFE_INTEGER, 0) 或负值边界 |
| 异常/压力 | 非数据类型、转换或大量调用 | 如 1000 次 add(1, 1),每次 expect(...).assertEqual(2) |
用例内调用接口方法,并用 expect(返回值).assertEqual(预期值)(或 assertContain 等)做断言。
生成测试用例时需遵守以下约定,本技能在生成代码时已落实基础实现。
constant.ets 中定义并导出,测试文件通过 import { ... } from './constant' 引用。生成器在首次生成前会检查 test 目录下是否存在 constant.ets,若不存在则自动创建并写入最小常量集(如 HILOG_DOMAIN、TEST_FILTER、VAL_0~VAL_3、STRESS_1000、MAX、MIN 等),后续可手动扩展。it() 用例块之间保留一个空行,便于阅读与 diff。0x0000、0、1000),改用 constant.ets 中的常量名(如 HILOG_DOMAIN、TEST_FILTER、STRESS_1000)。Indexdts_test_1.ets、Indexdts_test_2.ets),并在主入口中按序引入;生成器目前不自动拆分,需人工处理超大文件。生成内容已做到:使用 constant.ets 与导入常量、it() 间空行、hilog/expect 使用常量名、注释控制行宽;更多常量或拆分逻辑可在生成后手动补充。
根据 .ets 页面文件(如 pages/Index.ets)在 ohosTest 的 test 目录下生成 UI 测试套件,实现对页面的单元级 UI 测试。参考 HarmonyOS UITest 指南 与 arkXtest User Guide。
entry/src/main/ets/pages/Index.ets)、测试目录(如 entry/src/ohosTest/ets/test)、可选 Ability 名称(默认 EntryAbility)。<StructName>Ui.test.ets(如 IndexUi.test.ets),并在 List.test.ets 中注册该测试套。struct 名、@State 初始文本、Text(this.xxx) / Text('literal')、.onClick 内 this.xxx = 'yyy'、以及 Row() / Column() 布局。Row / Column(ON.type('Row') / ON.type('Column'))。ON.text('...')、assertComponentExist)。onClick 且会改变 @State 的控件,生成「findComponent → click → assertComponentExist(变化后文本)」用例。@kit.TestKit 的 Driver、ON、abilityDelegatorRegistry,以及 @ohos/hypium 的 describe / it / expect;常量从 constant.ets 引入(TEST_FILTER、UI_DELAY_MS)。# 必选:页面 .ets 文件、测试目录;可选:Ability 名、是否更新 List.test.ets
python3 src/skills/ohtest/uitest_gen.py \
--ets /path/to/entry/src/main/ets/pages/Index.ets \
--test-dir /path/to/entry/src/ohosTest/ets/test \
[--ability-name EntryAbility] \
[--no-update-list]
生成文件命名:<StructName>Ui.test.ets(如 IndexUi.test.ets),套件名为 <StructName>UiTest(如 IndexUiTest)。若 test 目录下已有 constant.ets,生成器会追加 UI_DELAY_MS(若缺失),与 dts 单元测试共用同一 constant 文件。
@State 字符串、Text(this.xxx) / Text('literal')、.onClick 内 this.xxx = 'yyy' 及 Row() / Column();复杂表达式或动态文本需生成后人工补充用例。# 必选:接口定义文件、测试目录;可选:模块名(默认 libentry.so)、是否更新 List.test.ets
python3 src/skills/ohtest/ohtest.py \
--dts /path/to/entry/src/main/cpp/types/libentry/Index.d.ts \
--test-dir /path/to/entry/src/ohosTest/ets/test \
[--module libentry.so] \
[--no-update-list]
生成文件命名:<基名>.test.ets,基名为接口文件名去掉特殊符号(如 Index.d.ts → Indexdts),故得 Indexdts.test.ets;套件名为基名+Test(如 IndexdtsTest),describe 与 export default function 分别为 IndexdtsTest、indexdtsTest。
Ability.test.ets(export default function abilityTest()、describe('ActsAbilityTest', () => { ... })、beforeAll/beforeEach/afterEach/afterAll、it('assertContain', 0, () => { ... expect(...).assertEqual(...) }))。Index.d.ts 的导出接口(如 add),导入方式与工程一致(如 import lib from 'libentry.so',调用 lib.add(...))。在正确的工作目录和环境(含 hdc 路径)下调用 developer_test 的 start.sh 执行 FUZZ 测试套。
test/testfwk/developer_test 下调用 ./start.sh。shutil.which("hdc") 查找 hdc。脚本会将 ${OHOS_SDK_PATH}/linux/toolchains(及 toolchains/bin 若存在)加入 PATH,以便框架找到 hdc;未设置 OHOS_SDK_PATH 时需保证系统 PATH 中已有 hdc。DEVTESTDIR 为 developer_test 的绝对路径,与框架约定一致。# 方式一:按测试套名执行(-ts 与 -ss/-tp 至少填其一)
python3 src/skills/ohtest/fuzztest.py run -ts GetAppStatsMahFuzzTest
python3 src/skills/ohtest/fuzztest.py run -ts GetAppStatsMahFuzzTest -p rk3568
python3 src/skills/ohtest/fuzztest.py run -ts GetAppStatsMahFuzzTest --dry-run
# 方式二:按子系统、部件执行(等价于 start.sh -p 3568 run -t FUZZ -ss customization -tp customization)
python3 src/skills/ohtest/fuzztest.py run -ss customization -tp customization -p 3568
python3 src/skills/ohtest/fuzztest.py run -ss customization -tp customization --dry-run
# 需收集覆盖率时再加 --coverage
python3 src/skills/ohtest/fuzztest.py run -ts GetAppStatsMahFuzzTest --coverage
python3 src/skills/ohtest/fuzztest.py help
| 参数 | 说明 |
|---|---|
-ts / --testsuite |
测试套名,如 GetAppStatsMahFuzzTest;与 -ss/-tp 至少填其一 |
-ss / --subsystem |
子系统,如 customization,与 start.sh 的 run -t FUZZ -ss 一致 |
-tp / --testpart |
部件,如 customization,与 start.sh 的 run -t FUZZ -tp 一致 |
-p / --product |
产品名,默认 rk3568(如 3568 则传 -p 3568) |
--coverage |
可选:附加 -cov coverage 收集覆盖率(拉取与分析时需设备上有 gcda) |
--dry-run |
仅打印将要执行的命令,不实际执行 |
执行前需:设备已连接、hdc 可用(设置 OHOS_SDK_PATH 或系统 PATH 中含 hdc)。
从工程目录扫描含 bundle.json 的部件(有 fuzztest 与无 fuzztest 的均列入同一张表);有 fuzztest 的解析 BUILD.gn 得到测试套件与 *_feature_coverage 覆盖率选项,无 fuzztest 的对应列填 无。表格增加一列:部件从 src 起的相对路径。默认输出 src/partwithfuzztest.md。
# 默认扫描整个 src(含 base、arkcompiler、developtools、device 等),输出到 src/partwithfuzztest.md
python3 src/skills/ohtest/find_fuzztest.py
# 仅扫描 base 目录
python3 src/skills/ohtest/find_fuzztest.py --root base
# 指定输出文件
python3 src/skills/ohtest/find_fuzztest.py -o /path/to/partwithfuzztest.md
| 参数 | 说明 |
|---|---|
--root |
相对 src 的扫描根目录,默认 .(整个 src);仅 base 时传 base |
--output / -o |
输出 Markdown 文件路径,默认 src/partwithfuzztest.md |
表格列:子系统 | 部件 | 相对路径(从 src 起) | 覆盖率编译选项 | Fuzztest 测试套件。无 fuzztest 的部件在覆盖率与测试套件列填「无」。
在 test/xts/acts 下扫描所有 BUILD.gn,识别 ohos_*_suite(如 ohos_app_assist_suite、ohos_js_app_suite、ohos_moduletest_suite)定义的 ACTS 测试套件,解析 hap_name、subsystem_name、part_name 及编译对象类型;统计子系统数、部件数、ACTS 测试套件数、目录数,并输出明细表到 src/all_acts.md。编译入口来自 bundle.json 的 test 节点://test/xts/acts/build:acts_group。
# 默认输出 src/all_acts.md
python3 src/skills/ohtest/find_actstest.py
# 指定输出文件
python3 src/skills/ohtest/find_actstest.py -o /path/to/all_acts.md
输出表格列:目录 | 子系统 | 部件 | 测试套件名 | hap_name | 编译对象。
脚本目录(相对 OpenHarmony src 或 napi_generator 布局):
napi_generator/src/skills/ohtest/
| 脚本 | 作用 |
|---|---|
dyn_static_workflow.py |
一站式:patch-sleep / build-static / sync-haps / pipeline |
compare_dyn_static.py |
配对统计 stats、设备跑测对比 run、已有报告 compare |
../ohbuild/ohbuild.py build-acts-static |
仅编译子系统 hap_static(也可) |
name ↔ name_static(两侧有 BUILD.gn)ohos_js_app(_static)_suite / hap_nameit('...');静态名去掉 Static 后与动态名相同则配对SKILL=/mnt/vdb/gitcode/master/src/napi_generator/src/skills/ohtest
OHBUILD=/mnt/vdb/gitcode/master/src/napi_generator/src/skills/ohbuild
SRC=/mnt/vdb/gitcode/master/src
SN=192.168.10.142:8710 # replace with the device serial
# A. 统计有多少动静态可对应用例
python3 $SKILL/compare_dyn_static.py stats --src-dir $SRC
# B. 编译 web 静态 HAP,并同步到 acts/testcases
python3 $SKILL/dyn_static_workflow.py build-static --src-dir $SRC --subsystem web
# 等价:python3 $OHBUILD/ohbuild.py build-acts-static --subsystem web --src-dir $SRC
# C. 设备上只跑可对应用例,出耗时差 CSV
python3 $SKILL/compare_dyn_static.py run --src-dir $SRC --sn $SN --paired-only
# D. 一键(可选先把静态 msSleep 全改成 1,再编再对比)
python3 $SKILL/dyn_static_workflow.py pipeline --src-dir $SRC --sn $SN \
--patch-sleep --paired-only
# 仅改 sleep(默认 msSleep(1))
python3 $SKILL/dyn_static_workflow.py patch-sleep --src-dir $SRC
# 仅同步 HAP
python3 $SKILL/dyn_static_workflow.py sync-haps --src-dir $SRC
# 只对比某一对套件 / 限制套件数
python3 $SKILL/compare_dyn_static.py run --src-dir $SRC --sn $SN \
--suite ActsWebComponentLifeCycleTest --paired-only
python3 $SKILL/dyn_static_workflow.py pipeline --src-dir $SRC --sn $SN \
--skip-build --paired-only --limit 5
输出:
out/<product>/suites/acts/acts/reports/dyn_static_pair_stats/out/<product>/suites/acts/acts/reports/dyn_static_cmp_<stamp>/compare.csv对设备上已有的 gcda 收集、生成 .gcov 并统计覆盖率(设备上需曾跑过带 -cov coverage 的 fuzz 测试才会产生 gcda)。
--coverage)python3 src/skills/ohtest/fuzztest.py run -ts GetAppStatsMahFuzzTestpython3 src/skills/ohtest/fuzztest.py run -ss customization -tp customizationpython3 src/skills/ohtest/fuzztest.py run -ts GetAppStatsMahFuzzTest --coveragepython3 src/skills/ohtest/coverage_analysis.py run -t customization -p rk3568customization 的 gcda。 python3 src/skills/ohtest/coverage_analysis.py run [-p rk3568]python3 src/skills/ohtest/coverage_analysis.py analyze [目录]${OHOS_SDK_PATH}/linux/toolchains(及 toolchains/bin)加入 PATH;未设置时需保证系统 PATH 中已有 hdc。run 拉取前,设备上需已有 gcda(即曾跑过带 -cov coverage 的 fuzz 测试)。清除 reports/obj 下的覆盖率相关文件(.gcda、.gcno、.cpp、.gcov),再从设备拉取 gcda、拷贝 gcno/cpp、执行 gcov,最后执行 analyze 输出统计。
python3 src/skills/ohtest/coverage_analysis.py clear-analyze
python3 src/skills/ohtest/coverage_analysis.py clear-analyze -p rk3568
先清除 reports/obj;再在设备上执行 fuzz 测试(调用 fuzztest.py);然后从设备拉取 gcda、生成 .gcov;最后执行 analyze 输出统计。
python3 src/skills/ohtest/coverage_analysis.py clear-rerun-fuzz-analyze
python3 src/skills/ohtest/coverage_analysis.py clear-rerun-fuzz-analyze -ts GetAppStatsMahFuzzTest -p rk3568
| 参数 | 说明 |
|---|---|
-ts / --testsuite |
fuzz 测试套名,默认 GetAppStatsMahFuzzTest |
-p / --product |
产品名,默认 rk3568 |
--device |
指定设备 ID |
--search-root |
设备上查找 *.gcda 的目录,可多次指定 |
| 参数 | 说明 |
|---|---|
-t / --target |
测试对象名(如 customization)。指定后:① 报告目录为 reports/obj_ |
--output-dir |
手动指定报告目录;与 -t 同时指定时以本参数为准。 |
analyze 会在指定目录下生成 analysis.md,内容包括:一、覆盖率汇总表;二、对覆盖率 <100% 的文件:未覆盖代码行(行号 + 代码内容)、测试建议(分支/错误处理/空指针等)。
根据 .gcov 覆盖率分析文件 结合对应 fuzztest 测试用例,生成「覆盖率缺失的测试用例」建议。输出包含:一、覆盖率缺失摘要;二、现有 fuzztest 目标;三、建议新增/修改的测试用例(按文件列出未覆盖行与涉及符号);四、新增/修改文件建议;五、构建与运行;六、预期对覆盖率的影响。参考此前新增 fuzzer(如 battery_stats_info_fuzzer)的流程:新增 fuzzer 目录与 BUILD.gn、在 group 的 deps 中注册、反序列化/API/分支类未覆盖时的 fuzzer 写法要点。
developer_test/reports/obj_<模块>_<id> 下的 .gcov 报告,需要针对未覆盖行给出新增 fuzzer、修改文件、构建运行与预期影响的结构化建议时。# 指定报告目录(通常为 reports/obj_<模块>_<id>);可选 --module、--output
python3 src/skills/ohtest/coverage_gap_tests.py analyze-gaps test/testfwk/developer_test/reports/obj_battery_statistics_2602051604
python3 src/skills/ohtest/coverage_gap_tests.py analyze-gaps test/testfwk/developer_test/reports/obj_battery_statistics_2602051604 --module battery_statistics
python3 src/skills/ohtest/coverage_gap_tests.py analyze-gaps test/testfwk/developer_test/reports/obj_battery_statistics_2602051604 -o coverage_gap_report.txt
# 不传报告目录时,若 reports 下仅有一个 obj_* 子目录则自动使用该目录
python3 src/skills/ohtest/coverage_gap_tests.py analyze-gaps
python3 src/skills/ohtest/coverage_gap_tests.py help
| 参数 | 说明 |
|---|---|
report_dir |
报告目录,如 developer_test/reports/obj_battery_statistics_2602051604;可省略并由脚本自动查找 |
--module / -m |
模块名(如 battery_statistics),用于解析现有 fuzztest 目标与模块路径 |
--output / -o |
将报告写入该文件;不指定则打印到 stdout |
test/fuzztest/BUILD.gn 的 deps 解析出的 FuzzTest 目标列表。BatteryStatsInfo::Unmarshalling)及示例行号与代码片段。<source_stem>_fuzzer/、*_fuzzer_test.cpp、BUILD.gn、project.xml、corpus/init);在 group 的 deps 中注册;反序列化/Setter·Getter·分支类未覆盖时的写法要点。./build.sh --build-target <NewFuzzTest> --gn-args <module>_feature_coverage=true、ohbuild 与 fuzztest/coverage_analysis 命令示例。