简介:面向需要批量自动发送微信招呼消息的开发与测试人员,这份资源以NotePadTest工程为样例,展示了微信API、自动化测试框架与Android签名机制三者在实际项目中的结合方式。压缩包共35个文件,大小约430KB,包含Java源码、class字节码、Robotium测试框架jar包、Android配置XML、PNG资源以及APK安装包等,覆盖从代码编写、资源编译到应用打包的完整过程。源码与字节码便于对照学习业务实现,jar包提供现成的测试依赖,XML和PNG对应界面布局与资源设计,APK可直接安装体验。资源也涉及重签名机制的背景知识,可帮助理解修改已签名应用后的重新签名流程及其注意事项。目前已有373人学习,适合初学微信自动化测试或Android签名机制的开发者在本地还原项目、参考其模块划分并扩展自己的测试脚本。
1. 微信自动打招呼:这功能到底怎么做,才不算踩线又真正能用
先说个反直觉的结论:微信自动打招呼这需求,真正让它翻车的从来不是“技术做不出来”,而是实现方式里埋的雷——协议封号、行为风控、消息频率,哪一条都比“写代码”本身更难啃。如果你只是想给微信客服做自动化测试,或者在合规前提下给某个内部工具加个批量初始化打招呼的入口,那不碰 Hook、不走外挂协议,用 Android 无障碍服务或者 ADB 模拟点击就能完成。
这篇文章我从选型开始讲,把“模拟人手的点击路径、随机间隔、重复内容过滤、异常恢复”这几个核心点逐个拆开,最后落到一份能跑通的思路和代码片段上。适合谁看?一类是做微信自动化测试的测试工程师,另一类是手里有十几个号需要做初始化流程验证的运营或开发者。两种情况都绕不开一个前提:频率必须压到和真人操作接近,否则一切自动化都是给你自己送封控样本。
先说结论:自动打招呼的本质不是“发消息”,而是“模拟用户界面操作”,所以它的技术栈天然偏向 UI 自动化,而不是协议层。这个区分,决定了你后续所有代码的写法。
2. 从原理到选型:为什么无障碍服务比协议 Hook 更适合“安全”的自动打招呼
2.1 两种实现路线的边界:协议 Hook 和 UI 自动化
微信自动打招呼,市面上的实现大致分两派。
第一派是协议派。直接调用微信内部接口,绕过界面,在后台完成打招呼动作。优点是速度快、批量成本低,缺点是这东西从底层就属于“外挂”范畴,风控识别非常敏感,而且每次微信版本升级,协议都要跟着重新逆向适配,维护成本高得吓人。我这里不教协议方向,不是说技术上做不了,而是它不符合自动化测试的定位,也不符合合规前提。
第二派就是 UI 自动化派,也是这篇笔记要展开的路线。它做的事情很简单:通过无障碍服务读取当前界面上的控件树,找到“通讯录”或“新的朋友”区域的“打招呼”按钮,然后模拟点击、模拟输入。整个过程相当于你拿了一根看不见的手指在操作手机,微信底层感知到的只是普通触摸事件,没有协议层的异常特征。
从自动化测试的角度来看,UI 自动化才是“正当”的那条路。它不修改微信客户端,不注入代码,奔跑在系统层面,跟人工划动屏幕没有本质区别,只是把操作录成了代码。
2.2 选型对比:无障碍服务、uiautomator2、Appium,到底用哪个
用 UI 自动化的思路来实现以后,接下来是工具选型问题。我给三个常见方向做个对比:
| 方案 | 运行位置 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|---|
| Android 无障碍服务 | 手机本地 | 无需电脑连接,可长时间运行,稳定性好 | 开发调试略麻烦,需要处理无障碍节点兼容 | 单一设备上的持续自动化 |
| uiautomator2 | 电脑通过 ADB 指挥 | 调试方便,代码直观,生态成熟 | 手机要开 USB 调试并保持连接 | 有小批量测试机集群 |
| Appium | 跨平台 | 多端通用,和测试框架结合紧密 | 启动慢,元素定位成功率受微信自定义控件影响大 | 已有 Appium 测试体系的团队 |
我这个项目用的是“无障碍服务 + 本地定时器”的组合,原因只有一个:自动打招呼这种任务的执行时机不固定(比如每天上午跑一次),手机得脱离电脑独立运行,uiautomator2 那套必须插着数据线,太长尾了。
说白了,如果你电脑就在旁边,选 uiautomator2 会更舒服;如果你要的是“把手机丢那儿自动跑”,无障碍服务是唯一稳定解。
2.3 无障碍服务的三大基础节点:按钮定位、文本输入、事件触发
无障碍服务的核心能力是通过 AccessibilityNodeInfo 访问屏幕上的节点树。做自动打招呼时,你只需要关注三种节点就行。
第一是入口按钮。从“微信”主界面进入“通讯录”,再进入“新的朋友”,这一步每个界面上都有固定的 TextView 或 Button 节点,我们通过 text 属性去匹配文字,比如“通讯录”“新的朋友”这样的字样。
第二是“打招呼”按钮。在“新的朋友”列表里,每个用户条目下面会有“打招呼”或“通过验证”之类的按钮,节点类型可能是 Button 也可能是 TextView,取决于微信的布局。这里不能用死板的条件查找,得用“当前节点父布局中带有某文本,并且节点自身可点击”的复合判断。
第三是输入框。点击“打招呼”以后弹出的界面是一个消息输入框(EditText),文本格式一般写成“你好,我是XXX,很高兴认识你”这类内容。
2.4 我验证过的最小可用方案:纯无障碍 + 定时器 + 控件过滤器
把以上三个节点串起来以后,最小可用方案就三块:
- 一个无障碍服务,监听窗口变化。
- 一个状态机驱动的流程控制:主界面 → 通讯录 → 新的朋友 → 第一条未打招呼用户 → 打招呼 → 输入内容 → 发送 → 返回。
- 每个操作之间插入 3 到 10 秒不等的随机等待。
下面是核心代码逻辑,我用伪代码加注释的方式来写,本意是给你一个实现参照而不是一个让你直接投入生产的成品。配上注释的代码我不附带完整运行环境,因为每个人的 Android 工程结构不一样,抄型别抄码。
// 无障碍服务核心入口类:自动打招呼的核心分发器 public class GreetAccessibilityService extends AccessibilityService { // 状态机:IDLE=空闲, TO_CONTACTS=去通讯录, TO_NEW_FRIENDS=去新的朋友, GREETING=打招呼, DONE=本轮完成 private String state = "IDLE"; @Override protected void onServiceConnected() { super.onServiceConnected(); // 做一个简单的定时触发,也可以保留外部广播作为触发器 startGreetLoop(); } @Override public void onAccessibilityEvent(AccessibilityEvent event) { // 监听窗口内容变化,每次界面跳转都会进入这里 if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && event.getEventType() != AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { return; } dispatchByState(); } private void dispatchByState() { switch (state) { case "IDLE": // 空闲时不做额外动作,等待定时器触发 break; case "TO_CONTACTS": // 关键场景:点击底部导航栏的“通讯录”入口 boolean a = clickNodeByText("通讯录", 0); if (a) { state = "TO_NEW_FRIENDS"; } else { state = "IDLE"; } break; case "TO_NEW_FRIENDS": // 进入通讯录后,顶部会出现“新的朋友”入口 boolean b = clickNodeByText("新的朋友", 0); if (b) { state = "GREETING"; } else { state = "IDLE"; } break; case "GREETING": // 在这里执行【查找未打招呼用户 -> 点击按钮 -> 输入内容 -> 发送】的子状态流转 processGreeting(); break; default: state = "IDLE"; break; } } /** 通过文本查找节点做模拟点击 */ private boolean clickNodeByText(String text, int index) { AccessibilityNodeInfo root = getRootInActiveWindow(); if (root == null) return false; List<AccessibilityNodeInfo> nodes = root.findAccessibilityNodeInfosByText(text); if (nodes != null && nodes.size() > index) { AccessibilityNodeInfo target = nodes.get(index); if (target.isClickable()) { target.performAction(AccessibilityNodeInfo.ACTION_CLICK); return true; } // 很多微信节点本身不可点击,但它的父节点可点击 AccessibilityNodeInfo parent = target.getParent(); if (parent != null && parent.isClickable()) { parent.performAction(AccessibilityNodeInfo.ACTION_CLICK); return true; } } return false; } }逻辑说明:这个服务在窗口内容变化时触发状态分发,每个状态只做一件事。clickNodeByText 里有个细节值得单独说——微信大量的业务按钮不是“原生可点击节点”,而是 TextView 外面套了一层可点击的父容器,所以代码里做了父节点回退查找。不加这个回退,你会发现按钮文字找到了但点了没有任何反应。
参数说明:index 参数用来处理同名节点的情况,比如“新的朋友”在当前界面可能出现两次(一次在列表标题、一次在功能入口),传 0 通常取到的是第一个匹配项。如果实际运行时发现点了没反应或点了不该点的位置,把这个参数微调成 1 或 2 就行,这是最传统的调试办法。
从这段代码可以看出,自动打招呼的逻辑本身并不复杂,复杂的是对不规则界面的兼容和防重复。
3. 从单步到全流程:把打招呼动作编排成一个稳定状态机,参数和关键节点一次理清
3.1 流程编排:每个界面的节点判断和等待策略
前面代码展示了怎么点击一个控件,但真实场景远不止点击一次能搞定。完整的自动打招呼流程,按界面划分大概是五段:
第一步:从主界面切换到“通讯录”Tab。
第二步:进入“新的朋友”列表页,等待列表加载完成。判断标准是当前界面出现了用户的头像节点或者“新的朋友”这个标题。
第三步:遍历未处理的用户条目。注意,不是所有出现在列表里的用户都能打招呼——已经添加过的、正在等待验证的,界面展示的按钮是不同的。“打招呼”文本的关键在于按钮上写着“打招呼”三个字,而不是灰色“已添加”或“等待验证”。
第四步:点击“打招呼”后,进入消息编辑界面,输入内容并点击“发送”。
第五步:发送完成后,连续执行两次返回操作,回到“新的朋友”列表页,然后滚动列表,找下一位用户。
每一步之间必须插入随机等待,我一般用 3000 毫秒到 8000 毫秒之间,低于 3 秒的间隔连续操作超过十次,就会开始触发微信的“操作过于频繁”提示,实测非常敏感。
3.2 数据初始化:打招呼内容从哪里来、怎么去重
自动打招呼的内容建议放在一个文本文件里,每行一条。数量不用多,准备十条左右轮换使用即可。为什么不能只写一条?因为对同一个用户,内容单调会被风控模型标记,理由很简单——真人不会每次发一样的消息。但如果你只是做自动化测试,要验证的是“打招呼流程能跑通”,那用一条固定内容也完全成立,这就是测试场景和运营场景的区别。
内容举例:
你好,我是某某科技的产品经理,想和您交流一下行业经验。 你好,看到你的头像很亲切,想认识一下。 你好,我是做ERP实施服务的,方便加个微信沟通吗?代码里读取这些内容的逻辑我用 Java 伪代码写一下:
// 读取外部配置文件,随机选取一条打招呼内容 public String getGreetMessage() { List<String> messages = new ArrayList<>(); // 读取 assets 下的 greet.txt,每行一条 InputStream is = getAssets().open("greet.txt"); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); String line; while ((line = reader.readLine()) != null) { if (line.trim().length() > 0) { messages.add(line.trim()); } } // 随机取一条:保证同一批测试里每条内容都有机会出现 Random random = new Random(); return messages.get(random.nextInt(messages.size())); }逻辑说明:asset 方式的好处是随 APK 打包,不需要外部存储权限。如果你想让运营随时改内容而不重装应用,可以改成读外部存储的指定文件夹,那样维护上更方便,但需要在 Android 6.0 以后处理运行时权限。
参数说明:消息列表里建议不要出现超长文本,微信的打招呼输入框能接受的字符数上限和普通消息一致,但如果你的内容里有换行符,有些版本会自动折行,容易被判定为异常输入。我一般把每条内容控制在 40 字以内,不带任何链接和特殊符号。
3.3 频率控制:这是整个项目里唯一值得写成“参数”的东西
无论你用无障碍还是 uiautomator2,自动打招呼频率都是决定生死的参数。我直接给出我在多个设备和账号上验证过的安全区间:
| 参数项 | 安全区间 | 风险提示 |
|---|---|---|
| 单次打招呼间隔 | 8~30 秒(随机) | 低于 5 秒有概率触发频率限制 |
| 每日打招呼上限 | 30~50 人 | 超过 80 人风险显著升高 |
| 单账号连续操作时长 | 15 分钟内停 5 分钟 | 不允许长时间连续操作 |
| 内容重复阈值 | 同一内容用 3 次后换下一条 | 内容相同比例过高容易被标记 |
这些参数没有官方依据,全是我在不同工具上反复测试观察到的经验值。不同微信版本的策略可能不同,保守点不吃亏。做自动化测试时我会把上限设置得更低,比如每天只打 10 个招呼,因为测试的目的本来就是验证流程稳定性,而不是真要把好友加满。
3.4 异常分支处理:找不到按钮、加载超时、卡在某个界面,怎么从状态机中恢复
自动打招呼运行中最大概率遇到的异常,不是代码报错,而是“界面元素和预期不符”。比如微信某次版本更新以后,“打招呼”按钮的文本从“打招呼”变成了“去打招呼”,你的 clickNodeByText("打招呼") 就会失效。处理方式有两种:
第一种是文本模糊匹配。
// 模糊匹配:包含“打招呼”三个字的节点都算命中 private boolean clickNodeByKeyword(String keyword) { AccessibilityNodeInfo root = getRootInActiveWindow(); if (root == null) return false; List<AccessibilityNodeInfo> nodes = root.findAccessibilityNodeInfosByText(keyword); for (AccessibilityNodeInfo node : nodes) { if (node.isClickable() || node.getParent().isClickable()) { return performClick(node) || performClick(node.getParent()); } } return false; }我个人更推荐这种方式,因为 findAccessibilityNodeInfosByText 在底层实现里本身就支持“包含查找”,对文本变化有更好的耐受度。
第二种是兜底逻辑。如果连续 60 秒都没有从某个状态推进到下一个状态,就强制回到主界面,通过按下“返回键或主页键”重置状态机。用这种“超时兜底”的好处是,就算某个界面卡死了,下一轮重试还会重新从主界面开始,不会停在死循环里。
4. 框架升级与组装:uiautomator2 版自动打招呼的轮询脚本和异常兜底
4.1 为什么纯无障碍方案不够,还要再搭一个 uiautomator2 尾巴
纯无障碍方案在单机上稳定,但有一个很难受的问题:它没有面向测试的报表能力。跑了多少条、成功了几个、失败原因是什么,无障碍服务全得自己往本地日志里写。对一个自动化测试项目来说,这远远不够看——你总得知道今天这个版本跑的通过率是多少。
所以我一般会再加一个 uiautomator2 的入口,作为“有电脑在场”时的补充手段。uiautomator2 的强项是轮询脚本直观,适合小批量、快速验证逻辑;弱势是必须保持手机和电脑的 ADB 连接,跑长尾任务不方便。
两块拼一起的逻辑是:日常无人值守跑用无障碍服务,版本升级后的回归验证用 uiautomator2,两边共享同一套参数(打招呼间隔、上限、内容模板)。
4.2 一套可运行的 uiautomator2 核心循环代码
以下是 uiautomator2 在 Windows 或 Linux 上执行自动打招呼流程的 Python 脚本示例。先安装依赖:pip install uiautomator2
import uiautomator2 as u2 import time import random # 连接设备:设备序列号可以通过 adb devices 获取 d = u2.connect("emulator-5554") # 唤醒屏幕并回到主界面 d.app_stop("com.tencent.mm") d.app_start("com.tencent.mm") time.sleep(5) # 定义点击文本的通用函数 def click_text(text, timeout=10): """在 timeout 秒内持续查找 text 节点并点击""" end_time = time.time() + timeout while time.time() < end_time: node = d(text=text) if node.exists: node.click() return True time.sleep(1) return False # 主流程:进入通讯录 -> 新的朋友 -> 逐个打招呼 def main(): if not click_text("通讯录"): print("未找到通讯录入口") return if not click_text("新的朋友"): print("未找到新的朋友入口") return # 开始轮询视图 for i in range(30): # 最多处理 30 个候选人 # 优先找“打招呼”文本,找不到则说明当前列表已到底或没有可处理的人 greet_btn = d(text="打招呼") if not greet_btn.exists: print(f"第 {i+1} 轮:没有找到可打招呼的按钮,结束") break greet_btn.click() time.sleep(3) # 输入框填入内容,这个节点通常靠近屏幕底部,用 className 定位更稳 box = d(className="android.widget.EditText") if box.exists: msg = "你好,我是做行业信息化的,希望有机会交流。" box.set_text(msg) time.sleep(2) # 点击发送按钮,微信的发送按钮 text 是“发送” d(text="发送").click() time.sleep(2) # 返回到列表页 d.press("back") time.sleep(2) d.press("back") time.sleep(random.randint(5, 12)) print(f"已完成第 {i+1} 个打招呼") # 兜底:如果主流程出现异常,重置应用 try: main() except Exception as e: print(f"发生异常: {e}") d.app_stop("com.tencent.mm") d.app_start("com.tencent.mm")逻辑说明:上面这个脚本的循环结构是“当前帧有按钮就打,没按钮就停”。它天然处理了列表滚动的问题——微信的新朋友列表是懒加载的,当你看不到“打招呼”按钮时,要么列表空,要么需要滚动。脚本里我卸载了滚动检测,是想先保持逻辑最简。你如果拿它做回归测试,只需要在循环末尾加上一行:
d(scrollable=True).scroll(steps=10)参数说明:d(text="打招呼")的返回值是 uiautomator2 的 UiObject 对象,.exists是它的状态属性,这一步会阻塞线程直到查找结束,算是 uiautomator2 比较坑同时也比较稳的地方。如果你在跑的时候发现打卡很慢,把 timeout 从 10 秒缩短到 5 秒即可,但代价是 Wi-Fi 网络较慢时可能漏点。
这段代码的“兜底逻辑”我用的是 try/except 包裹,但说句实话,uiautomator2 的异常远远不如无障碍服务的父节点兼容问题多。真正容易出问题的是d.app_start("com.tencent.mm")——微信包名在个别版本可能变了,真出现这种情况,需要先通过d.app_list()确认实际包名。
4.3 常见问题:uiautomator2 定位失败、输入框不弹、按钮“看得到点不到”
uiautomator2 定位失败通常有三类原因,一个个排查就行。
第一类:界面没有加载完就去找节点。微信页面是有动画过渡的,click_text("新的朋友")如果紧跟在点击“通讯录”后面,页面还在做左右平移,节点树还没刷新完成。解决方法是固定 sleep 3 秒以上再做后续定位,或者用d.wait_activity做进程等待。
第二类:节点被微信自定义的 SurfaceView 覆盖。视频号、朋友圈这类区域采用特殊渲染,uiautomator2 抓不到内部控件,但侧面按钮一般还是普通 View,这个碰到的概率不大。
第三类:“看得到点不到”。按钮的坐标位置被其他悬浮控件遮挡,或者按钮实际显示区域超出了屏幕。处理方式是用.click(offset=(0.5, 0.5))去做相对位置点击,而不是默认中心点点击。
如果你在跑自动打招呼脚本的过程中遇到“发送按钮点不了”,十有八九是输入法弹窗把按钮顶到屏幕外了。这种情况最直接的解决策略是关闭系统输入法的“安全输入”或“悬浮键盘”功能,换成系统默认 InputMethod,实测会顺很多。
4.4 消息发送后的状态确认,怎么做到不重复打第二次
自动打招呼最尴尬的事:消息发出去了,但脚本没“察觉”发送成功,于是滚到下一个流程时又对这个用户打了一次。要避免这种情况,关键在于发送动作完成后立刻检测界面变化。
我常用的一种判断法是:点击“发送”按钮后,查看当前窗口的节点树中是否还存在“打招呼”按钮或“发送”按钮。正常情况下,发送完成后,聊天界面会清空输入框内容并跳回列表页,“打招呼”按钮会变为灰色或消失。如果 5 秒后输入框里还是有内容,大概率没发出去。
还有一种兜底方法是记录已处理的用户 ID。微信新朋友列表的每个条目节点带有唯一的 resource-id 或内容描述,你用node.info提取该用户的文本摘要,存到本地 SQLite 或 SharedPreferences 里,下次处理前比对一次。这个方法不依赖界面变化,是更“测试工程师思维”的解法。
5. 自动打招呼避坑:六个真实踩坑记录,每条都对应一个具体原因
5.1 “打招呼”按钮文字变了,匹配直接失效
现象:某次跑脚本时发现,能进到“新的朋友”列表,但点不到“打招呼”按钮,日志提示“未找到节点”。
原因:微信版本更新后,“打招呼”文本被改成了“去打招呼”,你的 findAccessibilityNodeInfosByText 用的是精确匹配。
解决:改用包含匹配,用contains("打招呼")代替精确匹配。uiautomator2 里写成d(textContains="打招呼"),无障碍服务里用node.getText().contains("打招呼")做二次遍历过滤。
5.2 输入框定位到了但 set_text 半天没内容
现象:点击“打招呼”后进入了消息页,定位到 EditText,但set_text执行成功却没有文字出现。
原因:微信的输入框有自定义的 TextInputLayout 包装,set_text设置的是控件外层属性,没有触发内部 EditText 的文本变更监听。
解决:不要用 set_text,改用逐字符输入方式box.send_keys("你好,我是...")。或者先 click 一下输入框让光标聚焦,再使用剪贴板方式粘贴:设置剪贴板内容后执行长按粘贴操作。这两种方式都比 set_text 更接近真实用户行为。
5.3 跑了几条后界面弹出“操作过于频繁”强提示
现象:连续处理了 10 个用户后,微信弹了一个全屏对话框,提示操作频繁,后续所有节点定位失效。
原因:操作间隔太短,且行为模式太机械。微信的风控模型能检测到点击间隔非常均匀的自动化特征。
解决:把打招呼间隔从一个固定值改成随机值,比如random.randint(8, 25)秒;每处理 5 个用户后强制暂停 60 秒。如果遇到强提示,立即停止当前任务,手动跟在手机上划几下屏幕,等 30 分钟再继续。
5.4 真机上跑无障碍服务的入口开关被系统自动关掉
现象:服务跑着跑着,通知栏里显示“无障碍服务已关闭”,日志里服务 onDestroy 被调用。
原因:部分手机 ROM 会在内存紧张或检测到无障碍服务长时间运行时脑残式把它杀掉。
解决:在应用里引导用户把微信和当前应用都加入“电池优化白名单”和“后台运行白名单”。这个不是代码问题,是手机系统策略问题。做自动化测试时,我一般建议直接关掉系统的自动优化功能。
5.5 多个账号同时跑自动打招呼,ADB 连接冲突
现象:两个手机同时插到一台电脑上跑 uiautomator2 脚本,一个正常,另一个提示“device not found”。
原因:ADB 多设备使用时,u2.connect()如果不指定序列号,系统会默认连第一台设备,另一个设备则处于不可用状态。
解决:每次连接都显式传设备序列号。代码里写清楚:
devices = ["emulator-5554", "emulator-5556"] for i, device in enumerate(devices): d = u2.connect(device) # 每个设备一个独立任务5.6 滚动了列表,但“新的朋友”列表内容不刷新
现象:用scroll(steps=10)滑动列表后,程序仍然在重复点同一个“打招呼”按钮,好像滚动无效。
原因:微信的“新的朋友”界面在顶部有一个“全部”/“新的朋友”筛选切换,如果不切换筛选条件或不做下拉刷新,滚动列表只是视觉上移动,数据源没有更新。
解决:在滚动前先做一次下拉操作,然后点击列表首条目旁边的“更多”按钮触发一次刷新。或者干脆不滚动,每次打开应用时从头开始处理,处理完就退出。前者更符合“真人行为”,后者更简单直接。测试环境下选后者居多。
6. 从自动打招呼到一个通用 UI 自动化基座:这套思路最值钱的扩展方式
当你把自动打招呼跑稳定以后,你手上的这套东西其实已经是一套“微信核心流程遍历测试框架”了。它能帮你做的事远不止打招呼。
最直接的扩展是把这个状态机改成“微信自动化测试工具集”,内部维护一个可配置的任务队列。任务队列支持三种基本动作,这就够覆盖大部分日常测试诉求。
第一种动作是“走到指定界面”。比如从主界面到“发现”再到“视频号”,这个过程应该是一个可复用的导航函数。
第二种动作是“点击指定控件”。传入一个文本关键字和等待时间,自动点击。
第三种动作是“断言当前界面状态”。传入一个期望文本,代码里判断是否出现,出现即为 PASS,否则记录失败。
把这个队列配置化以后,你用一份 JSON 就能跑新用例,不用再改代码:
[ { "action": "navigate", "target": "新的朋友" }, { "action": "click", "target": "打招呼", "wait_after": 3000 }, { "action": "input", "target": "android.widget.EditText", "content": "你好,我是做行业信息化的。", "wait_after": 2000 }, { "action": "click", "target": "发送" }, { "action": "assert_display", "target": "新的朋友", "wait_timeout": 5000 } ]以上 JSON 表示一个完整的“从新的朋友列表页发起打招呼并验证回跳”用例。它的可读性比写在代码里的流程强很多,测试人员不用懂 Java 或 Python 也能参与编辑用例。
如果要把它做得更完整,我建议把“验证回跳”这个动作独立成一个工具方法,每次测试用例结束都必须走到一个已知的基准界面。这是我做过自动化测试之后养成的习惯——所有自动化用例结束态必须可预期,不能停在一个未定义的状态里。拿自动打招呼的场景说,就是发送完之后必须验证回到列表页,没回去就重试,重试三次失败就报警。
另外一点可以顺手做的是把每次自动打招呼的耗时、成功数、失败数写到本地 CSV 文件里,原因很简单:哪怕不受控,后面你反推“为什么某天被封”时,这份数据就是你唯一的后悔药。
我从那以后每次搭建类似功能,都会强制走一遍“先定状态、再定等待、最后定兜底”的流程,不会因为逻辑简单就省略兜底。部署之前再冷启动跑三遍完整流程,验证不会在同样的地方翻车两次。
希望这套拆解能帮你在自动打招呼这件事上少踩几个我能想到的坑。
本文还有配套的精品资源,点击获取