微信扫码
与创始人交个朋友
我要投稿
随着手机市场的多元化趋势的持续加剧,App测试领域所承受的考验愈发严峻,测试人员需要覆盖的品牌、操作系统、系统版本数量呈现爆炸性增长,这无疑极大的增加了测试工作的复杂度和工作量。
综上所述,如何在有限且紧迫的时间内,实现高效且全面的测试覆盖,已成为我们亟需攻克的核心难题。而针对已知的历史场景,我们可以通过编写自动化测试脚本来提升测试质量和效率。然而,对于新需求的测试交付提效,我们的突破口又在哪里?
泰勒在
《科学管理原理》
中提出的任务管理法强调了对工作的科学分析和分解,将复杂繁琐的任务划分为多个简单、标准化的子任务。这种任务分解的思路为并行处理提供了可能。通过合理的任务划分和分配,不同的任务或子任务可以由不同的工人或团队并行执行,从而提高整体的工作效率
。
从泰勒管理学的任务拆解法中可提取关键信息:子任务、标准化,并行。
我有个大胆的想法...
让 1 = N ?从“串行测试” 到“并行测试”
子任务: 三端(Android
、iOS
、HarmonyOS
)的功能测试、兼容性测试都可拆分为不同的子任务;
标准化: 功能测试、兼容性测试的覆盖场景为准出条件;
并行: 测试人员通过标准化流程并行执行多个子任务;
我们也向一线业务测试团队征集了关于多机同步方案的一些想法,从可落地的角度了解业务测试团队在实际应用中的主要诉求,主要包括如下几个方面:
在移动端测试领域,面对测试量庞大的行业痛点,业界也有不少多机联动方案来提高测试效率,我们选取了具有代表性的一些大厂及测试服务提供商的实现方案做了一个简单调研。
公司 | 蚂蚁SoloPi | Testin | 泽众 云真机 |
---|---|---|---|
关键特性 | 元素级别同步 | 相对坐标同步 | 相对坐标同步 |
实现方案 | AccessibilityService+图像+无线adb | 云真机 | 云真机 |
支持平台 | Android | Android+iOS | Android+iOS |
支持联动设备数 | 理论上不限 | 8 | 4 |
上手难度 | 高 | 低 | 低 |
是否支持溯源 | 否 | 是 | 是 |
是否开源 | 是 | 否 | 否 |
SoloPi
通信层面是通过无线adb且不涉及Web画面传输,所以理论上联机设备不限量,精细化程度也做到了元素级别的同步。但是SoloPi
是基于Android系统的产品,相较于基于云真机的Testin和泽众无法提供跨平台服务,且上手难度较高需要配置各种前置条件。
鉴于以上情况,为了更好地满足货拉拉在多机同步测试方面的需求,我们决定抛弃现有的开源方案,转而自研贴合货拉拉业务测试场景的多机同步工具。我们将充分借鉴SoloPi
在元素级别同步方面的优势,同时克服其在跨平台兼容性和上手难度上的不足,通过深度定制和优化,期望能够打造出一款既高效又易用、能够全面满足货拉拉多机同步测试需求的解决方案。
结合业界方案的调研与业务上对多机同步使用的诉求,再者,货拉拉在云真机建设的探索与成功实践(感兴趣的小伙伴可以参考我们之前发布的相关文章《货拉拉云真机平台的演进与实践》),我们决定基于货拉拉云真机来实践多机同步的测试。主要因为云真机有以下几个优势:
至于云真机的部署、通信、投屏等详细方案,感兴趣的同学可以查看之前的文章,这里是详细介绍多机同步的的实践,整体技术架构如图:
EventBus: EventBus
是分配消息的一种实现机制,它拥有部署在Agent
的手机建立的websokect长连接的管理及操控权限。消息则是通过EventBus
的发送到Agent
的端,最后由Agent
注入到手机执行消费。
eventBus.emit('syncAppointControl',
{
udId: serial,
action: JSON.stringify(MITT_MESSAGE),
}) //操控消息
eventBus.emit('syncKeyevent', JSON.stringify(message)) //键盘事件
Message: 为了降低维护成本并确保未来对HarmonyOS
的顺利接入,我们在消息传递层面设计了一套统一的协议。这套协议的核心思想是将浏览器层面拦截到的用户操作转换为预定义的协议消息体,然后通过EventBus
进行分发。不同接入的系统(如Android
、iOS
、HarmonyOS
)在接收到这些消息后,会根据各自平台的特性进行解析和定制化适配。
import {
ANDROID,
IPHONE,
MITT_MESSAGE,
TOUCH_U,
TOUCH_D,
TOUCH_M,
LONG_PRESS,
SWIPE,
TAP,
KEY_EVENT,
INPUT_EVENT,
SHELL_EVENT,
OPEN_APP,
OPEN_IOSAPP,
STOP_APP,
STOP_IOSAPP,
INSTALL,
UN_REINSTALL,
REINSTALL,
UNINSTALL,
UNLOCK
} from '../Sync/ActionEvent'
实现精准控制,在《货拉拉App录制回放的探索与实践》我们有过相关OCR
的介绍,这里我们不赘述原理,重点是决定复用相关的能力,采用Paddleocr来实现元素的精准控制,相对于基于系统AccessibilityService
和xcuitest
控制同步,基于OCR
来实现精准控制有以下几个优点:
OCR
的输入永远只是一张图片,可以忽略不同平台(Android
、iOS
、HarmonyOS
)自身服务的差异化,甚至对于我们后续对小程序的兼容成本非常小。如果采用控件元素同步,需要对当前自动化框架进行特殊改造,实现成本非常大。ocr识别流程
WebdriverAgent
框架,获取元素就非常耗时,导致响应速度也不能满足业务上的需求。然而OCR
的飞速发展,响应速度大有可观,GPU模式下基本都在200ms以内,比较简单的页面甚至可以在100ms左右返回结果,CPU则是500ms~1000ms左右,而且响应速度极其不稳定,至于GPU为什么比CPU要快,简单一句话概括就是并行多线程批量处理与单线程处理的区别,也完美印证本次实践主题的思想。Paddleocr
的版本参数及运行硬件可供参考:Paddleocr | 检测模型 | 识别模型 | GPU | CPU |
---|---|---|---|---|
2.7.1 | ch_PP-OCRv4_det | ch_PP-OCRv4_rec | NVIDIA GeForce RTX 4090 | Intel(R) Core(TM) i9-13900K |
Paddleocr
的能力和其提供官方通用模型,对于我们来说,虽然是开箱即用,但是还有一部分移动端的特殊场景检测效果并不理想,比如对于同行相近的文本、边界场景识别结果并不是我们想要的。
所以我们决定在官方的通用检测模型上进行调优,训练适合货拉拉移动端UI页面检测的模型。
我们选择了PP-OCRV4_det(best_accuracy.pdparams)
作为学习模型,为了确保模型能够学习到最真实、最具有代表性的数据特征。每当自动化测试过程中遇到失败的Case,我们都会将其保存下来。这些失败的Case通常包含了各种复杂和多样的文本场景,如不同的字体、大小、颜色、背景以及排列方式等。由于自动化测试是持续进行的,因此我们可以实时地获取到最新的失败Case,并将其添加到训练数据集中。
我们采用了半自动标注的方式,对已经筛选出来用于调优训练的数据进行了细致的特征划分。这一过程中,借助了官方提供的PPOCRLabel
工具。然而,标注过程并非一帆风顺,特别是面对文本拼接问题时,由于官方通用模型倾向于将一整行内容作为一个整体进行标注,必须手动进行分割。这项繁琐而细致的工作耗费了笔者整整两天的时间。此外,数据标注并非一次性任务,而是一个持续的过程。随着模型的训练和测试,可能会发现新的标注需求或错误,需要及时进行调整和修正。因此,模型的优化工作是一个循环迭代的过程,不断优化和完善标注结果,以支持模型的持续改进和提升。
对于已标注的数据集,我们采用了一系列特殊的图像处理技术来丰富数据多样性,旨在显著提升模型的泛化能力,具体措施包括:
数据集的增强处理,有效扩展了训练样本的覆盖范围,帮助模型更好地适应复杂多变的实际应用场景。
基于货拉拉App真实测试场景训练的模型识别效果:
针对用户在实际操作过程中可能因点击到文本区域外而导致操作无法正确响应的问题,我们旨在通过扩大文本有效点击区域来提升用户体验。虽然官方提供的det_db_unclip_ratio
参数可以调整DB模型输出框比例,但考虑到其对文本检测准确度产生负面影响,并不推荐直接修改该参数。更为优雅的解决方案是:在文本检测和识别流程完成后,对识别结果进行后处理,通过放大文本框的方式增加有效点击区域。为确保放大后的文本框之间不产生重叠,具体核心在于尝试使用最大的扩展像素值进行放大,并在检测到重叠时逐步减小扩展像素值,直至所有文本框均不再重叠或达到最大迭代次数。以下是该算法的实现步骤:
通过这种方法,我们可以在不牺牲文本检测准确度的情况下,有效扩大用户的文本有效点击区域,从而提升用户体验和防止“手抖”现象。
def is_overlapping(box1, box2):
min_x1, min_y1 = min(pt[0] for pt in box1), min(pt[1] for pt in box1)
max_x1, max_y1 = max(pt[0] for pt in box1), max(pt[1] for pt in box1)
min_x2, min_y2 = min(pt[0] for pt in box2), min(pt[1] for pt in box2)
max_x2, max_y2 = max(pt[0] for pt in box2), max(pt[1] for pt in box2)
return not (min_x1 >= max_x2 or min_x2 >= max_x1 or min_y1 >= max_y2 or min_y2 >= max_y1)
def expand_box(box, expand_pixels):
min_x = min(point[0] for point in box) - expand_pixels
max_x = max(point[0] for point in box) + expand_pixels
min_y = min(point[1] for point in box) - expand_pixels
max_y = max(point[1] for point in box) + expand_pixels
return [[min_x, min_y], [max_x, min_y], [max_x, max_y], [min_x, max_y]]
def adjust_boxes(ocr_results, max_expand_pixels, min_expand_pixels=0, step=1):
original_boxes = [result['bounding_box'] for result in ocr_results]
current_expand = [max_expand_pixels] * len(original_boxes)
def adjust_single_box(idx):
nonlocal current_expand, original_boxes
expanded_boxes = [expand_box(box, current_expand[idx]) for idx, box in enumerate(original_boxes)]
for j in range(len(expanded_boxes)):
if idx != j and is_overlapping(expanded_boxes[idx], expanded_boxes[j]):
if current_expand[idx] > min_expand_pixels:
current_expand[idx] = max(current_expand[idx] - step, min_expand_pixels)
return adjust_single_box(idx)
elif current_expand[j] > min_expand_pixels:
current_expand[j] = max(current_expand[j] - step, min_expand_pixels)
return adjust_single_box(j)
return expanded_boxes, False
iteration = 0
while True:
no_collision = True
for i in range(len(original_boxes)):
expanded_boxes, collision_detected = adjust_single_box(i)
if collision_detected:
no_collision = False
break
if no_collision:
break
iteration += 1
if iteration > 1000:
break
return expanded_boxes
def zoom_in(ocr_results):
max_expand_pixels = 10
return adjust_boxes(ocr_results, max_expand_pixels, min_expand_pixels=1, step=0.5)
调整前效果与扩大后效果如下图所示:
文本区域周围最大偏移10个像素,如果出现相邻文本框,动态调整间距,直至矩阵框不交割。
多机同步过程中,若流量开销过大,可能导致区域网络拥堵(目前工区网络的使用已经达到极限)和实际体验的卡顿。解决方案通常涉及优化传输数据及同步策略:比如压缩传输数据,减少不必要的通信。
多机同步中会关闭过渡动画,目前机房大部分设备基本控制在(静置)10kb~( 高度渲染)500kb左右每秒的带宽消耗。
PD2130:/ $ settings put global window_animation_scale 0
PD2130:/ $ settings put global transition_animation_scale 0
PD2130:/ $ settings put global animator_duration_scale 0
在自动化测试过程中,突然出现的弹窗可能会影响测试结果,同样在多机同步测试过程中,如果突然出现弹窗,对用户来讲就意味着增加的额外的操作成本。对于弹窗,我们主要分为两大类:系统弹窗和App弹窗。
主要系统的升级提醒,对于华为、荣耀等品牌的手机,我们可以通过禁用系统应用的方式来屏蔽更新
adb shell pm disable-user com.huawei.android.hwouc
adb shell pm disable-user com.hihonor.ouc
adb shell pm disable-user com.meizu.flyme.update
adb shell pm disable-user com.bbk.updater
但对于iPhone,普遍的方法是通过安装某个过期Beta更新描述文件来屏蔽正式版本的更新,但是此方法对于新加入的手机需要经常换描述文件,且每次配置比较繁琐。我们采用在局域网内屏蔽掉苹果的更新域名地址,目前可以说是一劳永逸的方法,以下两个域名屏蔽后,验证下来只会屏蔽掉系统更新服务,不会影响到其它服务。
mesu.apple.com
appldnld.apple.com
主要是App向系统的权限申请弹窗,一般是位置定位、网络申请权限、SD卡申请权限等。Android
各种系统弹窗的碎片化主要是由于Android
的开放性和多样性,导致不同设备制造商、不同系统版本以及不同定制版本的Android
系统对弹窗的设计、实现和展示方式存在显著差异。最简单粗暴的方式就是如何屏蔽掉这些,而不是通过脚本去自动化处理,因为随着系统及ROM的升级,自动化脚本也需要随之维护。
不同品牌权限申请弹窗
我们通过运行在手机内拥有DeviceOwner权限的天宫管家来控制App的权限申请弹窗。关于天宫管家App,我们之前的文章也有相关的引用,这里我们再简单介绍一下实现方法。
<?xml version="1.0" encoding="utf-8"?>
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<force-lock />
<expire-password />
<encrypted-storage />
<disable-camera />
<limit-password />
<watch-login />
<reset-password />
<wipe-data />
</uses-policies>
</device-admin>
public class DevAdminReceiver extends DeviceAdminReceiver {
@Override
public void onDisabled(Context context, Intent intent) {
super.onDisabled(context, intent);
}
@Override
public void onNetworkLogsAvailable(Context context, Intent intent, long batchToken, int networkLogsCount) {
super.onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount);
}
@Override
public void onPasswordChanged(Context context, Intent intent, UserHandle userHandle) {
}
@Override
public void onSystemUpdatePending(Context context, Intent intent, long receivedTime) {
super.onSystemUpdatePending(context, intent, receivedTime);
}
@Override
public void onUserAdded(Context context, Intent intent, @NonNull UserHandle newUser) {
super.onUserAdded(context, intent, newUser);
}
}
ComponentName adminComponentName = new ComponentName(context, DevAdminReceiver.class);
DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
Android端5台同步下单测试演示
Android+iOS同步下单测试演示
Android
和iOS
平台上的功能实现与交互效果,加快产品验收测试流程。“道阻且长,行则将至,行而不辍,未来可期”。——《荀子·修身》
面对移动端测试的繁琐性、平台多样性以及覆盖设备广泛的复杂挑战,本次探索是我们从单线程的传统测试模式向多线程、多设备同步测试的一次重要实践与大胆尝试。正如《荀子·修身》所言:“道阻且长,行则将至,行而不辍,未来可期”。我们坚信,通过持续的技术创新与实践努力,依然可以不断提升测试效率与质量。
HarmonyOS NEXT
,想象一次测试便能同时验证四端设备的便捷与高效。53AI,企业落地应用大模型首选服务商
产品:大模型应用平台+智能体定制开发+落地咨询服务
承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-11-21
ima.copilot-腾讯智能工作台的产品设计和技术实现
2024-11-21
深度解析AI智能助手系统架构:数据接入到平台管理的全景指南
2024-11-20
微软推出 Copilot Actions了
2024-11-20
看完Rokid 2024发布会:期待一个可替换手机的硬核新品 Rokid Glasses
2024-11-15
腾讯出品windows桌面端copilot,终于等到你
2024-11-15
树莓派AI套件:如何将混乱的数据变成有序的魔法
2024-11-13
LLM实践系列-昇腾910B上进行Qwen2.5推理
2024-11-13
谷歌推出教育AI产品“Learn About”!步步引导,多模态呈现
2024-03-30
2024-05-09
2024-07-07
2024-07-01
2024-06-24
2024-07-23
2024-06-08
2024-06-05
2024-06-21
2024-07-11
2024-11-12
2024-11-11
2024-10-29
2024-10-22
2024-10-18
2024-10-16
2024-10-15
2024-10-10