微信小程序UI自动化测试实战:基于Minium的完整方案与避坑指南
1. 项目概述:为什么微信小程序UI自动化测试是刚需?
做微信小程序开发的朋友,尤其是负责质量保障的测试同学,最近几年应该都感受到了一个明显的痛点:版本迭代越来越快,功能越来越复杂,但回归测试的时间窗口却越来越短。手动点点点,不仅效率低下,还容易因为疲劳导致漏测。特别是涉及到支付流程、多页面跳转、复杂表单交互的场景,每次发版前都提心吊胆。我自己带团队做中大型小程序项目时,就深刻体会到,没有一套可靠的UI自动化测试体系,根本不敢谈敏捷开发和快速交付。
UI自动化测试,简单说就是让脚本模拟真人去操作小程序界面,完成一系列预设的检查点。它的核心价值不在于替代人工探索性测试,而是把那些重复、固定、高频的回归测试任务自动化,把人解放出来去做更有价值的测试设计、用户体验评估和复杂场景挖掘。对于小程序这种承载关键业务(如电商、服务预约、内容付费)的载体,UI自动化是保障核心链路稳定性的“守门员”。
那么,做小程序UI自动化,和做Web或App自动化有什么不同?难点在哪?首先是环境隔离。小程序运行在微信这个“超级App”内部,你无法像测浏览器一样直接打开一个URL,也无法像测原生App一样完全控制设备。其次,小程序有自己独特的架构,分为视图层(Webview)和逻辑层(JSCore),双线程通信,这给元素定位和数据获取带来了挑战。最后,微信的生态是封闭的,很多底层接口和调试协议不对外开放,工具链的选择相对有限。
基于这些背景,这次我想系统性地分享一下,我们团队从零到一搭建微信小程序UI自动化测试体系的完整实践。这套方案已经稳定运行了两年多,覆盖了核心业务模块,在每次迭代中为我们节省了超过70%的回归测试时间。我会从工具选型、环境搭建、脚本编写、元素定位策略、断言设计,一直讲到持续集成和真机运行,过程中踩过的坑和总结的经验技巧,都会毫无保留地分享出来。
2. 核心工具链选型与深度解析
工欲善其事,必先利其器。选择一套趁手、稳定且官方支持的工具链,是自动化测试成功的第一步。经过多方调研和实际踩坑,我们最终锁定了以微信开发者工具和Minium测试框架为核心的方案。
2.1 为什么是Minium?
在项目初期,我们评估过几种主流方案:
- 基于Appium测试微信:这是最直观的想法,把微信当作一个App,用Appium去驱动。但实际尝试后问题很多:小程序页面是动态加载的Webview,上下文(Context)切换频繁且不稳定;元素定位依赖XPath或Accessibility ID,但小程序编译后的节点结构复杂,定位器非常脆弱,一个小程序框架升级就可能导致大量用例失败。
- 基于Selenium测试开发者工具:通过WebDriver协议控制开发者工具的模拟器。这条路理论上可行,但开发者工具本身并非为自动化设计,协议不稳定,且无法覆盖真机特有的环境(如手机权限、网络状态)。
- 微信官方小程序自动化SDK:这是微信开放平台提供的一套Node.js SDK,它通过WebSocket与开发者工具或真机上的调试端口通信,可以直接调用小程序的API、操作页面元素。这是最接近小程序运行时的方案。
- Minium:这是微信官方基于Python封装的一套测试框架,底层调用的正是小程序自动化SDK。它提供了更友好、更Pythonic的API,并且集成了测试组织、断言、报告生成等能力,是“开箱即用”的完整解决方案。
我们选择Minium,主要基于以下几点考量:
- 官方背书,生态兼容:由微信团队维护,与微信开发者工具和小程序基础库的更新保持同步,长期稳定性有保障。不用担心因为微信底层接口变动而导致框架失效。
- 协议级控制,能力强大:它直接与小程序调试基础库通信,可以获取到真实的页面数据、调用wx对象上的任何接口(如
wx.login,wx.request),甚至可以向小程序的逻辑层注入代码片段,这对于准备测试数据或Mock接口响应极其有用。 - 元素定位策略针对性强:Minium提供了专门为小程序设计的元素选择器,如
.wx-selector,能更精准地定位到小程序组件,比通用的XPath稳定得多。 - Python生态丰富:我们的开发团队对Python更熟悉,利用
pytest、allure等成熟的生态可以快速搭建测试工程和生成美观的报告。
注意:Minium目前主要支持在微信开发者工具的模拟器环境和Android真机上进行自动化测试。对于iOS真机,官方支持有限,通常需要借助其他工具配合或采用云测平台(如微信小程序云测)的方案。这是选型时必须明确的限制条件。
2.2 环境搭建的魔鬼细节
安装Minium看似简单,但有几个细节不注意,后面会处处碰壁。
第一步:安装微信开发者工具必须使用稳定版,并且建议关闭自动更新。因为Minium的版本与开发者工具版本存在绑定关系,不匹配可能导致连接失败。去微信开放平台下载安装即可。
第二步:安装Minium使用pip安装是最简单的方式:pip install minium。但这里有个关键点:强烈建议使用虚拟环境(如venv或conda)。因为Minium依赖一些特定的库版本,避免与项目中其他Python包的版本冲突。
第三步:配置开发者工具这是最容易出错的一步。打开微信开发者工具,依次进入【设置】->【安全设置】,打开服务端口。你会看到一个端口号,通常是9527,记下它。 然后,你需要用命令行启动开发者工具,并指定这个端口和你的项目路径。光在GUI里打开项目是不够的,自动化连接需要命令行启动。创建一个启动脚本(如start_ide.bat或start_ide.sh):
# Windows (bat) "D:\Program Files (x86)\Tencent\微信web开发者工具\cli.bat" auto --project “你的小程序项目绝对路径” --auto-port 9527 # macOS/Linux (sh) /Applications/wechatwebdevtools.app/Contents/MacOS/cli auto --project “你的小程序项目绝对路径” --auto-port 9527运行这个脚本,开发者工具会以无头模式(或最小化)启动,并监听指定端口。
第四步:编写第一个连接脚本创建一个Python文件,比如test_first.py:
import minium class FirstTest(minium.MiniTest): def test_hello(self): # 连接到正在运行的开发者工具实例 self.mini = minium.Minium({ "project_path": “你的小程序项目绝对路径”, # 必须和启动时一致 "dev_tool_path": “微信开发者工具可执行文件路径”, # 如 cli.bat 的路径 "platform": "ide", # 使用开发者工具模拟器 }) # 跳转到首页 self.app.redirect_to("/pages/index/index") # 这里可以开始你的页面操作和断言 print("连接成功,页面已跳转!")运行这个测试,如果能看到开发者工具模拟器自动打开并跳转到首页,恭喜你,环境打通了!
实操心得:很多同学在这一步卡住,报错“连接超时”或“找不到项目”。请务必检查三点:1. 开发者工具是否通过命令行指定端口和项目启动;2.
project_path是否是完全相同的绝对路径;3. 开发者工具版本与Minium版本是否兼容(查看Minium文档的版本说明)。一个快速验证的方法是,手动在开发者工具GUI中打开项目,然后在Minium配置中设置"platform": "ide"并注释掉dev_tool_path,它会尝试连接当前已打开的GUI实例。
3. 元素定位:从入门到放弃?不,到精通
元素定位是UI自动化的基石,也是脚本稳定性的生命线。小程序经过编译渲染后的DOM结构,和我们在WXML里写的并不完全一样,这增加了定位难度。
3.1 Minium提供的定位器
Minium提供了多种定位方式,我们需要根据场景灵活选用:
WXML选择器:这是最推荐的方式,类似于CSS选择器,但针对小程序组件进行了优化。
.class:通过组件的class定位,如.btn-submit。#id:通过组件的id定位,如#login-btn。element:通过组件标签名定位,如view,button。[attribute=value]:通过属性定位,如[data-testid=\"submit\"]。
# 定位一个class为primary的button button = self.page.get_element(\".btn-primary\") # 定位一个id为user-avatar的image组件 avatar = self.page.get_element(\"#user-avatar\")XPath:万不得已时使用。因为小程序的渲染层结构可能变化,XPath路径会非常脆弱。
# 尽量避免使用绝对路径 # bad: /page/view[2]/view[1]/button # good: 结合有稳定属性的父节点 self.page.get_element(\"view.custom-form\").get_element(\".submit-btn\")文本内容定位:
text='登录'。这种方式直观,但受国际化(多语言)和UI文案变更影响最大,慎用。# 定位文本内容为“登录”的元素 login_element = self.page.get_element(\"text='登录'\")
3.2 打造稳定的定位策略:给元素加上“测试钩子”
为了从根本上解决定位脆弱的问题,我们必须在开发阶段就介入,建立约定。这就是“测试驱动开发”思想在UI层的一种实践。
方案:统一使用 这样做的好处: 正确的做法是使用 避坑指南:小程序中,通过 有了稳定的元素定位能力,我们就可以设计测试用例了。一个好的测试脚本,应该像一篇逻辑清晰的文章,包含准备、执行、验证、清理四个阶段。 我们使用 自动化测试最大的挑战之一是状态管理。你不能让测试用例相互污染。 策略一:每个用例独立账号与数据。对于需要登录的测试,我们使用一批固定的测试账号。在 策略二:使用后端测试接口或数据库夹具。对于涉及创建订单、提交表单等产生数据的操作,一定要有数据清理机制。通常我们在测试环境的服务端提供专门的测试接口,用于创建测试数据和清理数据。在用例的 Minium提供了丰富的API来模拟复杂手势。 实操心得:手势操作的坐标点需要根据模拟器或真机的实际分辨率来计算。一个技巧是,先使用开发者工具的“选择元素”功能,大致估算出目标元素的中心坐标。更稳健的做法是,通过获取元素的位置和大小信息来计算相对坐标。 断言是测试的灵魂。对于小程序,我们不能只断言页面元素是否存在,更要断言业务逻辑是否正确,数据流是否通畅。 UI状态断言:最基础的断言,检查元素可见性、文本、样式等。 页面数据断言:通过 应用全局状态断言:通过 网络请求断言:通过Mock或拦截的方式,断言发起的网络请求是否符合预期(参数、URL)。这需要用到Minium的 UI自动化中,“等待”和“断言”是孪生兄弟。很多间歇性失败都是因为等待不充分。 脚本写好了,在本地跑通只是第一步。要让自动化测试产生最大价值,必须把它集成到CI/CD(持续集成/持续部署)流水线中,并能在真机上运行。 核心思路是:在代码推送或合并请求时,自动在一个干净的Linux环境中安装依赖、启动无头模式的微信开发者工具、运行测试套件并生成报告。 以GitHub Actions为例的配置文件 注意事项:微信开发者工具的Linux版本可能更新不及时,且无头模式支持可能不完善。在实际生产中,更稳定的做法是使用Docker镜像。社区有一些维护了微信开发者工具和Minium环境的Docker镜像,可以大大简化CI环境配置。你需要做的就是拉取镜像,挂载你的项目代码,然后执行测试命令。 在模拟器上跑通,不代表在真机上没问题。真机测试能发现更多与设备相关的问题,如屏幕适配、手势响应、性能等。 Minium支持连接Android真机进行自动化。前提是: 配置修改:在测试配置中,将 真机测试的挑战: 我们的策略:在CI流水线中,日常在模拟器上运行全量测试。每晚定时任务,在几台固定的Android真机上运行核心冒烟测试用例。真机测试用例需要编写得更健壮,包含更多的异常处理。 即使方案再完善,在实际运行中也会遇到各种稀奇古怪的问题。这里记录几个我们踩过的典型深坑和解决方案。 我们有一个用例是测试支付成功后的页面跳转。在模拟器上一直很稳定,但在某台特定真机上,偶尔会失败。失败时的现象是:支付成功后,应该跳转到“支付成功”页,但脚本却断言到了一个“订单详情”页的元素。 排查过程: 解决方案:在测试脚本中,支付操作完成后,不仅等待“支付成功”页面出现,还多等待一小段时间(比如1秒),然后直接去断言“订单详情”页的元素。同时,更根本的解决方式是,让开发同学优化这里的页面跳转逻辑,避免在 这个案例告诉我们,UI自动化测试不仅能发现前端的bug,有时也能暴露出业务逻辑或时序上的深层问题。测试脚本的稳定性,最终依赖于被测系统本身的可测试性。推动开发团队编写更稳定、更易于测试的代码,是自动化测试成功的长远之道。><!-- 在WXML中 --> <button>submit_btn = self.page.get_element(\"[data-testid='btn-login-submit']\") phone_input = self.page.get_element(\"[data-testid='input-phone']\")># 错误示范 list_item = self.page.get_element(\".list-item\") # 可能还没加载出来 list_item.click()wait_for或get_elements并判断数量。# 正确做法1:使用wait_for等待某个条件满足 self.page.wait_for(\"list-item\", max_timeout=10) # 等待类名为list-item的元素出现 # 正确做法2:获取元素列表,并操作符合条件的某一项 elements = self.page.get_elements(\".list-item\") self.assertGreater(len(elements), 0, \"列表项未加载\") target_item = elements[2] # 操作第三项 target_item.click() # 正确做法3:结合data-testid和文本内容精确定位 # 假设我们要找一个标题为“测试商品A”的项 all_items = self.page.get_elements(\"[data-testid='product-item']\") for item in all_items: # 获取该元素内部的文本节点内容,需要先获取其子文本元素 # 注意:.inner_text 或 .text 可能不直接暴露,需要根据实际情况获取 # 一种常见模式是,标题是一个独立的view或text子元素 title_element = item.get_element(\".product-title\") # 假设标题有类名 if title_element.inner_text == \"测试商品A\": item.click() breakget_element获取到的对象,其inner_text或text属性有时可能为空或不是预期值。这是因为文本可能被包裹在子text节点里。更可靠的方法是先定位到具体的文本子元素,或者使用page.data获取逻辑层数据来进行断言。UI断言和Data断言结合使用,是保证测试健壮性的关键。4. 核心测试流程设计与脚本编写实战
4.1 测试用例结构设计
pytest作为测试运行器,利用Minium提供的minium.MiniTest基类。一个典型的测试文件结构如下:import minium import pytest class TestLoginModule(minium.MiniTest): @classmethod def setUpClass(cls): """测试类开始前执行一次,用于初始化""" super(TestLoginModule, cls).setUpClass() # 可以在这里启动小程序,或做一些全局Mock print(\"Login Test Suite Started.\") def setUp(self): """每个测试方法开始前执行,用于重置状态""" super(TestLoginModule, self).setUp() # 确保每次测试都从首页开始 self.app.redirect_to(\"/pages/index/index\") # 等待首页加载完成 self.page.wait_for(\"page-index\", max_timeout=5) def tearDown(self): """每个测试方法结束后执行,用于清理""" # 例如:清除本次测试产生的本地缓存 self.app.clear_storage() super(TestLoginModule, self).tearDown() def test_login_with_phone_success(self): """测试手机号登录成功流程""" # 1. 准备:可能不需要额外准备,setUp已回到首页 # 2. 执行:模拟用户操作链 self.page.get_element(\"[data-testid='tab-my']\").click() # 点击‘我的’页签 self.page.get_element(\"[data-testid='btn-to-login']\").click() # 点击去登录 phone_input = self.page.get_element(\"[data-testid='input-phone']\") phone_input.input(\"13800138000\") # 输入手机号 self.page.get_element(\"[data-testid='btn-get-code']\").click() # 点击获取验证码 # 这里需要处理验证码,通常需要Mock或从测试环境获取 code_input = self.page.get_element(\"[data-testid='input-sms-code']\") # 假设我们通过后门接口或Mock数据拿到了验证码 test_sms_code = self.mock_get_sms_code(\"13800138000\") code_input.input(test_sms_code) self.page.get_element(\"[data-testid='btn-login-submit']\").click() # 点击登录 # 3. 验证:断言预期结果 # 验证1:页面跳转或UI变化 self.page.wait_for(\"[data-testid='page-user-center']\", max_timeout=5) # 等待跳转到用户中心页 # 验证2:用户登录状态(通过页面数据或Storage) user_info = self.app.get_storage(\"user_info\") self.assertIsNotNone(user_info, \"用户信息未成功存储\") self.assertEqual(user_info[\"phone\"], \"13800138000\", \"登录用户手机号不一致\") # 验证3:页面元素状态(如显示用户名) welcome_text = self.page.get_element(\"[data-testid='text-welcome']\").inner_text self.assertIn(user_info[\"nickname\"], welcome_text) def test_login_with_wrong_code(self): """测试验证码错误流程""" # ... 类似上面的操作,输入错误验证码 self.page.get_element(\"[data-testid='btn-login-submit']\").click() # 验证:出现错误提示 toast_text = self.page.get_element(\".wx-toast\").inner_text # 注意toast可能需要特殊方式获取 self.assertEqual(toast_text, \"验证码错误\") # 验证:仍然停留在登录页 current_page = self.app.get_current_page() self.assertIn(\"login\", current_page) # 更多测试用例...4.2 处理登录态与测试数据隔离
setUp中,先调用小程序的wx.clearStorage清理本地状态,然后执行登录操作。或者,更优雅的方式是利用Minium的mock_wx_method能力,在用例开始时直接Mockwx.login或wx.request返回成功的登录态,绕过真实的登录流程。这样测试的就是登录后的业务逻辑,而不是登录接口本身。def setUp(self): super().setUp() # 方法1:直接跳转到登录后页面,并注入登录态(适用于测试登录后功能) self.app.redirect_to(\"/pages/user/index\") # 向AppService注入代码,设置全局用户数据 self.app.evaluate(\"function(){ app.globalData.userInfo = {nickName: \'测试用户\'}; }\")() # 同时设置Storage self.app.set_storage({\"user_info\": {\"nickname\": \"测试用户\", \"uid\": \"test_001\"}}) # 方法2:Mock网络请求(推荐) # 假设登录接口是 /api/login self.app.mock_wx_method(\"request\", function_name=\"login_api_mock\") # 这个function_name对应一个在mock文件中定义的函数setUp中调用创建接口,在tearDown中调用清理接口。4.3 复杂交互:下拉刷新、滑动、长按
# 模拟下拉刷新 # 首先需要定位到可滚动区域,通常是scroll-view或page本身 scroll_view = self.page.get_element(\"scroll-view\") # 从坐标(200, 100)滑动到(200, 300),模拟下拉 scroll_view.swipe(start_x=200, start_y=100, end_x=200, end_y=300, duration=500) self.page.wait_for(\".loading\", max_timeout=3) # 等待加载动画出现 self.page.wait_for(\".loading\", max_timeout=5, is_disappear=True) # 等待加载动画消失 # 模拟滑动切换Tab tab_bar = self.page.get_element(\".tab-bar\") # 横向滑动 tab_bar.swipe(start_x=300, start_y=50, end_x=100, end_y=50, duration=300) # 模拟长按 element_to_longpress = self.page.get_element(\"[data-testid='item-menu']\") element_to_longpress.long_press() # 等待上下文菜单弹出 self.page.wait_for(\".action-sheet\", max_timeout=2)ele = self.page.get_element(\".some-element\") rect = ele.rect # 返回 {left, top, width, height} center_x = rect[\"left\"] + rect[\"width\"] / 2 center_y = rect[\"top\"] + rect[\"height\"] / 2 # 然后基于center_x, center_y进行滑动操作5. 断言的艺术:不止于UI,更要深入Data
5.1 多维度断言策略
self.assertTrue(submit_btn.is_enabled(), \"提交按钮应处于可点击状态\") self.assertEqual(title_ele.inner_text, \"订单详情\", \"页面标题不正确\") self.assertIn(\"btn-disabled\", some_ele.get_attribute(\"class\"), \"元素应包含禁用样式\")page.data获取当前页面逻辑层的数据,这是小程序测试特有的强大能力。# 假设页面data中有一个list page_data = self.page.data self.assertIsInstance(page_data[\"productList\"], list, \"productList应为数组\") self.assertGreater(len(page_data[\"productList\"]), 0, \"商品列表不应为空\") # 检查数据内容 first_product = page_data[\"productList\"][0] self.assertEqual(first_product[\"status\"], 1, \"第一个商品状态应为上架\")app.global_data或wx.getStorage检查全局状态。global_data = self.app.app.global_data self.assertTrue(global_data[\"isLoggedIn\"], \"全局登录状态应为真\") # 或者检查Storage cart_info = self.app.get_storage(\"cart_info\") self.assertEqual(cart_info[\"total_count\"], 3, \"购物车商品总数应为3\")mock_wx_method来Hookwx.request。5.2 实现一个健壮的“等待与断言”组合
def wait_and_assert(self, selector, expected_text, timeout=10): """ 一个自定义的等待并断言文本的辅助函数。 它会持续检查元素是否存在且文本匹配,直到超时或成功。 """ start_time = time.time() while time.time() - start_time < timeout: try: element = self.page.get_element(selector) if element.inner_text == expected_text: return True # 成功,直接返回 except Exception: pass # 元素未找到或文本不匹配,继续循环 time.sleep(0.5) # 短暂休眠,避免CPU空转 # 循环结束仍未成功,进行最终断言(会抛出明确的失败信息) element = self.page.get_element(selector) # 这里如果找不到会抛异常 self.assertEqual(element.inner_text, expected_text, f\"元素{selector}文本最终未匹配预期\") return False # 使用示例 self.wait_and_assert(\".toast-text\", \"提交成功\", timeout=5)6. 持续集成与真机运行:让自动化融入开发流程
6.1 搭建基于GitLab CI/GitHub Actions的流水线
.github/workflows/minium-test.yml:name: Minium UI Tests on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.9' - name: Install dependencies run: | pip install minium pytest allure-pytest - name: Download and install WeChat DevTools (Linux) run: | # 这里需要从微信开放平台下载Linux版开发者工具,可能需要处理下载链接和许可协议 # 这是一个示例,实际链接和安装步骤请参考官方文档 wget -q https://dldir1.qq.com/WechatWebDev/linux/wechat-devtools-latest.tar.gz tar -xzf wechat-devtools-latest.tar.gz -C /opt/ echo '/opt/wechat-devtools-latest' >> $GITHUB_PATH - name: Start WeChat DevTools in headless mode run: | # 启动无头模式的开发者工具,并指定项目路径和端口 /opt/wechat-devtools-latest/cli auto --project ${{ github.workspace }}/your-miniprogram-path --auto-port 9527 & sleep 15 # 等待工具启动完成 - name: Run tests with Minium run: | # 运行测试,指定配置文件,并生成Allure结果 python -m pytest tests/ --minium-config config.json --alluredir=./allure-results - name: Upload Allure report uses: actions/upload-artifact@v3 if: always() # 即使测试失败也上传报告 with: name: allure-report path: ./allure-results6.2 真机自动化测试实践
adb devices确认设备已连接。platform从"ide"改为"android",并指定设备序列号或adb路径。// config.json { "project_path": "/path/to/your/project", "platform": "android", "device_desire": { "serial": "你的设备adb序列号" // 可通过 adb devices 查看 }, "headless": false // 真机测试通常需要显示界面 }connect_to_device和launch_app等相关API。7. 常见问题排查与性能优化实录
7.1 高频问题速查表
问题现象 可能原因 排查步骤与解决方案 连接开发者工具失败 1. 开发者工具未以 --auto-port启动。
2. 端口被占用。
3. 项目路径不一致。
4. 版本不兼容。1. 检查命令行启动参数,确保端口开放。
2. 使用netstat -ano | findstr :9527查看端口状态。
3. 对比脚本和启动命令中的项目绝对路径。
4. 核对微信开发者工具和Minium的版本号。元素找不到 (NoSuchElement) 1. 页面未加载完成。
2. 定位器写错或元素属性已变更。
3. 元素在scroll-view内未滚动到可视区域。
4. 页面有iframe或原生组件(如video)。1. 在操作前增加 page.wait_for()。
2. 使用开发者工具检查元素实际渲染后的结构,使用>脚本执行速度慢1. 使用了大量 time.sleep。
2. 断言前没有智能等待。
3. 网络请求或动画未完成就进行下一步。1. 用 wait_for或自定义等待函数替代固定休眠。
2. 优化定位器,减少全局搜索(如避免用*)。
3. 监听页面/数据变化作为等待条件,而非单纯等待时间。在真机上运行不稳定 1. 设备性能差异。
2. 系统弹窗干扰。
3. 小程序本身在真机上有兼容性问题。1. 增加操作间的间隔时间,使用更稳定的坐标点击代替元素点击。
2. 脚本开头尝试关闭常见系统通知(需设备权限)。
3. 将不稳定的用例标记为@flaky,并分析是否是小程序代码问题。无法获取 inner_text文本可能不在当前元素上,而在子节点中。 使用 element.inner_wxml查看内部结构,或使用element.get_element(\"text\").inner_text先定位子文本节点。Mock网络请求不生效 1. Mock时机不对,请求已发出。
2. Mock函数作用域或返回值格式不对。1. 在跳转到页面或触发操作之前就设置好Mock。
2. 仔细阅读Minium文档,确保Mock函数返回符合wx.request回调结构的对象。7.2 性能优化技巧
setUp中做好充分的复位工作(清理Storage、跳转回首页、Mock初始状态)。class LoginPage: def __init__(self, mini): self.mini = mini self.page = mini.app.get_current_page() @property def phone_input(self): return self.page.get_element(\"[data-testid='input-phone']\") def login(self, phone, code): self.phone_input.input(phone) # ... 其他操作 return UserCenterPage(self.mini) # 返回下一个页面的对象pytest-xdist插件进行并行测试。需要为每个进程分配不同的开发者工具端口和小程序项目实例(可以复制多份项目目录),避免冲突。page.capture()方法。同时,配置详细的日志记录,帮助回溯执行过程。7.3 一个真实的排错案例:支付回调后的页面闪烁
onShow生命周期里有一段逻辑:如果检测到某个标志位,又会用wx.redirectTo跳转到“订单详情”页。onShow中做可能引起循环跳转的判断。
