在移动端自动化测试领域,Flutter生态中的patrol_log组件因其出色的日志捕获和测试轨迹记录能力而备受开发者青睐。随着鸿蒙HarmonyOS的快速崛起,如何将这套成熟的测试方案无缝迁移到鸿蒙平台,成为许多技术团队面临的实际挑战。
这个项目本质上要解决三个关键问题:
我去年主导过金融类App的鸿蒙适配项目,当时最头疼的就是测试环节的断层——原有的Flutter自动化测试方案在鸿蒙设备上会出现大量误报。经过两周的踩坑,最终通过改造patrol_log的核心模块实现了95%以上的用例复用率。
采用分层适配架构:
code复制[Flutter侧核心] --Dart FFI--> [鸿蒙Native层] --HiLog--> [鸿蒙系统日志]
│ │
└──[结构化转换层]←───┘
关键决策点:
日志格式统一化处理:
dart复制// 原始Flutter日志结构
{
"level": "INFO",
"message": "Button tapped",
"timestamp": 1634567890123,
"stackTrace": [...]
}
// 鸿蒙HiLog输出格式
HiLog.info(
tag: "PATROL",
label: "[%{public}s] %{public}s",
params: [level, message]
);
解决方案是开发LogNormalizer组件,在Native层实现格式转换:
cpp复制void normalizeLog(JNIEnv *env, jobject thiz, jstring jsonLog) {
const char *jsonStr = env->GetStringUTFChars(jsonLog, nullptr);
// 解析JSON并提取字段
rapidjson::Document doc;
doc.Parse(jsonStr);
// 构造HiLog兼容格式
HiLogPriority priority = convertLevel(doc["level"].GetString());
HiLogPrint(LOG_APP, priority, LOG_TAG,
"[%{public}s] %{public}s | seq=%{public}lld",
doc["level"].GetString(),
doc["message"].GetString(),
generateHarmonySequenceId(doc["timestamp"].GetInt64()));
}
鸿蒙侧必备组件:
bash复制# DevEco Studio中配置gradle
implementation 'io.github.harmony-patrol:logadapter:1.0.2'
implementation 'com.huawei.hilog:hilog:3.0.5'
Flutter侧改造:
yaml复制dependencies:
patrol_log: ^2.4.1
ffi: ^2.0.1
path_provider_hmos: ^1.0.0 # 鸿蒙专属路径处理
Dart侧FFI接口定义:
dart复制typedef NativeLogFn = Void Function(
Pointer<Utf8> jsonLog,
Int32 urgency,
);
typedef DartLogFn = void Function(
Pointer<Utf8> jsonLog,
int urgency,
);
final _nativeLib = DynamicLibrary.open('libpatrol_adapter.z.so');
final _logToHarmony = _nativeLib
.lookupFunction<NativeLogFn, DartLogFn>('logToHarmony');
void logToHarmony(String json, {LogLevel level = LogLevel.info}) {
final jsonPtr = json.toNativeUtf8();
_logToHarmony(jsonPtr, level.index);
calloc.free(jsonPtr);
}
Native层对应实现:
cpp复制extern "C" JNIEXPORT void JNICALL
Java_com_example_patroladapter_LogBridge_logToHarmony(
JNIEnv *env,
jobject thiz,
jstring jsonLog,
jint urgency) {
const char *jsonStr = env->GetStringUTFChars(jsonLog, nullptr);
HiLogPriority priority = convertUrgency(urgency);
normalizeAndSend(env, jsonStr, priority);
env->ReleaseStringUTFChars(jsonLog, jsonStr);
}
鸿蒙特有的分布式断言流程:
typescript复制// 设备A发起断言
assertAcrossDevices({
target: 'all', // 或指定deviceId
condition: 'textContains("确认")',
timeout: 5000
});
// 设备B的响应处理
onAssertReceived((request) => {
const localResult = checkCondition(request.condition);
sendAssertResponse({
requestId: request.id,
deviceId: getLocalDeviceId(),
result: localResult
});
});
问题现象:
鸿蒙3.0设备上偶现日志顺序错乱,导致测试用例失败
根因分析:
解决方案:
cpp复制// 在Native层添加逻辑时钟
std::atomic<uint64_t> global_sequence(0);
uint64_t generateHarmonySequenceId(int64_t flutter_time) {
uint64_t local_seq = global_sequence.fetch_add(1);
return (flutter_time << 16) | (local_seq & 0xFFFF);
}
压测数据:
| 场景 | 原始方案 | 优化后 |
|---|---|---|
| 单设备1000条日志 | 12.3s | 4.7s |
| 3设备分布式断言 | 2.1s | 0.8s |
关键优化点:
日志分类策略:
断言设计原则:
mermaid复制// 注意:根据规范要求,此处不应使用mermaid图表,改为文字描述
分布式断言应遵循"三阶验证法":
1. 本地快速检查:当前设备是否满足条件
2. 组内同步验证:同组设备状态一致性检查
3. 全局最终确认:主设备汇总所有响应
hilog -x命令实时过滤测试日志dart复制patrol().mark(
label: "重要检查点",
screenshot: true,
attach: currentState
);
这套方案经过验证可适用于:
在智能家居控制App的测试中,我们利用改造后的patrol_log成功捕获到多设备协同时的边界条件问题,如: