当前位置: 首页 > news >正文

【Appium 系列】第18节-重试与容错 — 移动端测试的稳定性保障

配套代码:utils/retry.pytests/test_login_api.py

说明:本节所有代码示例均来自一个真实的移动端自动化测试项目,已做模糊化处理。


为什么需要重试

移动端测试比 Web 测试更容易出现偶发性失败。以下几种情况在本地和 CI 上反复出现:

  • 网络波动:Appium 调用find_element时底层发起的 HTTP 请求超时,抛出TimeoutException: An element could not be located on the page using the given search parameters
  • 元素加载慢:页面渲染被动画或懒加载阻塞,在元素存在前执行了click(),触发NoSuchElementException: An element could not be located
  • 键盘弹出延迟send_keys()执行时输入框尚未获得焦点,驱动报InvalidElementStateException: Element must be user-editable to sendKeys
  • 动画未结束:页面切换动画仍在运行时点击下一个元素,抛出ElementClickInterceptedException: Element is not clickable at point (x, y)

这些失败不是代码逻辑 bug,而是环境或时序导致的不稳定。重试 2-3 次后,绝大部分情况下用例能正常通过。utils/retry.py提供了retry_on_failure装饰器和RetryHelper工具类来解决这类问题。


重试装饰器

utils/retry.py中的retry_on_failure是一个装饰器,直接加在测试函数或页面操作方法上即可启用自动重试。

from utils.retry import retry_on_failure class TestLogin: @retry_on_failure(max_attempts=3, delay=2.0) def test_login_with_retry(self, driver): """带重试的登录测试""" from pages.login_page import LoginPage login_page = LoginPage(driver) login_page.input_phone_email("test_user@example.com") login_page.input_password("test_password") login_page.click_login_button() assert login_page.is_on_home_page()

参数说明

  • max_attempts:最大尝试次数(包括首次执行),默认 3。最后一次失败后不再重试,直接抛出异常。
  • delay:每次重试间隔,单位秒,默认 1.0。重试前通过time.sleep(delay)等待。
  • exceptions:需要捕获并重试的异常类型元组,默认(Exception,)即捕获所有异常。可以精确指定只重试特定异常,例如exceptions=(TimeoutException, NoSuchElementException)

执行流程

  1. 首次执行函数,成功则直接返回结果。
  2. 捕获到exceptions中指定的异常时,记日志并等待delay秒后重试。
  3. 第 2~N 次重复上述流程。
  4. 所有max_attempts次均失败后,抛出最后一次捕获的异常。
# 精确捕获特定异常,避免因 AssertionError 误重试 @retry_on_failure(max_attempts=3, delay=2.0, exceptions=(TimeoutException, NoSuchElementException)) def test_element_interaction(self, driver): ...

RetryHelper 辅助类

除了装饰器,utils/retry.py还提供了RetryHelper工具类,适用于不能或不想用装饰器的场景——比如在页面对象(Page Object)的某个方法内部对单个操作做重试。

retry_operation

对任意可调用对象执行重试,适合在 Page Object 中精细控制:

from utils.retry import RetryHelper class LoginPage: def click_login_with_retry(self): """对单次点击操作做重试,不波及整个用例""" RetryHelper.retry_operation( self.click_login_button, max_attempts=3, delay=1.0 )

签名:retry_operation(operation, max_attempts=3, delay=1.0, exceptions=(Exception,), *args, **kwargs)

retry_until_success

重试直到满足自定义成功条件,适合轮询等待某个状态:

RetryHelper.retry_until_success( self.click_login_button, max_attempts=10, delay=0.5, success_condition=lambda: self.is_element_displayed("xpath", "//*[@text='首页']") )

success_condition是一个可调用对象,返回True视为成功。这对于动画未结束、数据尚在加载的场景非常实用——不是单纯等固定时间,而是等到条件成立。


重试策略选择

策略适用场景参数建议
固定延迟网络波动、元素加载慢delay=2.0
指数退避服务端限流、资源竞争延迟递增:2s → 4s → 8s
快速重试键盘弹出延迟、动画未结束delay=0.5

指数退避可以在retry_on_failure基础上手动实现:

def retry_with_backoff(max_attempts=3, base_delay=1.0): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): last_exception = None for attempt in range(max_attempts): try: return func(*args, **kwargs) except Exception as e: last_exception = e if attempt < max_attempts - 1: delay = base_delay * (2 ** attempt) logger.warning(f"等待{delay}秒后重试: {e}") time.sleep(delay) raise last_exception return wrapper return decorator

常见坑与报错

以下是在实际项目中踩过的坑,每个都附有具体报错信息。

坑 1:重试覆盖了真正的代码 bug

AssertionError: Expected True but got False assert login_page.is_on_home_page()

如果你用@retry_on_failure(max_attempts=5, delay=1.0)不加exceptions参数,默认捕获Exception,连AssertionError也会被兜住重试。测试报告里显示"重试后通过",但实际是业务逻辑有问题。应通过exceptions参数限定只重试环境类异常,让断言失败直接暴露。

坑 2:重试间隔太短,重试等于白试

selenium.common.exceptions.TimeoutException: Message: timeout (WARNING: The server did not provide any stacktrace information)

页面上一个接口通常需要 1-3 秒返回数据,如果重试间隔设成delay=0.3,页面还没加载完就重试,同样会再次超时。推荐至少 1.5-2 秒。

坑 3:重试次数太多,拖慢整个测试集

Test session running in 12m 34s ...

100 个用例,每个重试 3 次 × 2 秒延迟 = 多出 600 秒(10 分钟)。如果每个用例都无脑加@retry_on_failure,测试集时间膨胀严重。只在确实偶发的用例上加重试,能通过find_elementWebDriverWait解决的优先用等待。

坑 4:装饰器忘了加@wraps,pytest 报告中函数名变成 wrapper

tests/test_login.py::test_login_with_retry → wrapper # 函数名被覆盖

utils/retry.py中已经写了from functools import wraps并在内层函数上加@wraps(func)。如果你自己写重试装饰器时漏了这一行,func.__name__会变成wrapper,pytest 报告中看到的测试名称将是wrapper而非原始函数名,导致无法匹配 Allure 报告中的测试用例。

坑 5:exceptions参数传了错误类型导致异常逃逸

@retry_on_failure(max_attempts=3, exceptions=(TimeoutException))

元组写法少了逗号,(TimeoutException)会被 Python 解析为单个表达式而非元组。正确的写法是(TimeoutException,)。漏掉逗号后,重试装饰器不会捕获任何异常,偶发失败直接报错退出。

坑 6:不适合重试的场景强行加重试

AttributeError: 'NoneType' object has no attribute 'click' driver = None # driver 未初始化

driverNone、测试数据错误、配置写错——这些属于一次性失败,重试 100 次结果一样。先定位根因,不要用重试掩盖配置或数据问题。


哪些场景适合用重试

  • 元素定位超时(页面加载慢)
  • 网络请求超时(网络波动)
  • 偶发性断言失败(动画未结束,元素尚未到达预期状态)

哪些场景不适合用重试

  • 逻辑错误(代码 bug,重试多少次都一样)
  • 数据错误(测试数据不对,重试后仍然一样)
  • 配置错误(driver 没初始化、API 地址不对)

总结

重试是应对移动端测试不稳定性的实用手段,但需要搭配正确的参数和策略。utils/retry.py提供了装饰器和工具类两套方案——装饰器适合整个测试函数级别,RetryHelper适合细粒度控制单次操作。用好exceptions参数避免误吞断言失败,控制delaymax_attempts防止测试集膨胀。能通过显式等待(WebDriverWait+expected_conditions)解决的问题,优先用等待,重试作为兜底方案。

http://www.jsqmd.com/news/874203/

相关文章:

  • 2026泳池建造厂家推荐:酒店洗浴、户外泳池、泳池工程、泳池水处理、泳池设备、洗浴厂家、洗浴工程、洗浴改造、洗浴施工选择指南 - 优质品牌商家
  • 锌钢护栏网技术解析:四川公路铁路护栏网、四川双边丝护栏网、四川围栏网、四川学校球场围栏、四川市政道路护栏网、四川牛栏围栏网选择指南 - 优质品牌商家
  • 2026年Q2四川应急物资厂家评测:应急消防设备厂家/应急物资厂家电话/抗洪抢险应急设备/消防工具厂家/消防智能设备/选择指南 - 优质品牌商家
  • 2026成都靠谱金属建材回收公司推荐:工厂废料回收/工地废料回收/库房物资回收/废旧机器回收/废铁回收/废铜回收/选择指南 - 优质品牌商家
  • 毕业论文神器!2026年必备AI论文软件榜单,免费版也能写合规初稿
  • 2026年Q2西南地区测绘仪租赁服务机构排行盘点:华测rtk/华测无人船/地形测量/大疆无人机/徕卡全站仪/手持扫描仪/选择指南 - 优质品牌商家
  • 2026年当下河北工程网格布实力厂商剖析与精准选型指南 - 2026年企业推荐榜
  • 2026年成都学历提升选校指南:口碑机构成都市成华区新概念外语培训学校深度 - 2026年企业推荐榜
  • 2026年当下耐磨输送带选型指南:鼎基机械输送有限公司深度解析 - 2026年企业推荐榜
  • 2026年5月,如何精准对接武汉地区优质橡胶助剂供应商? - 2026年企业推荐榜
  • 2026年第二季度,昆明膜结构源头工厂如何引领市场新需求 - 2026年企业推荐榜
  • 【独家首发】Claude代码生成能力黄金分级标准(L1-L5):附赠可落地的团队接入评估清单(限前500名下载)
  • AI知识管理不是工具升级,而是教学主权重构:一位特级教师用18个月完成“教案→知识流→认知干预”三级跃迁(全程数据脱敏实录)
  • Claude+Query Store双引擎协同优化(仅限AWS RDS与Azure SQL托管实例的私有API调用指南)
  • 合同纠纷律师哪个好?李静律师:复杂商事合同争议解决专家 - 外贸老黄
  • 当Agent开始质疑你的原始数据——AI驱动的数据质量自治体系构建(含动态污点追踪与因果溯源模块)
  • 2026气体扩散层权威供应商精选推荐:气体扩散过滤板、气体扩散金属板、气体扩散钛板、气体扩散钛滤板、电解槽滤板选择指南 - 优质品牌商家
  • 2026防爆门厂家推荐:快速门推荐/折叠门厂家/折叠门推荐/推拉门厂家/推拉门推荐/提升门推荐/泄爆窗厂家/泄爆门厂家/选择指南 - 优质品牌商家
  • 3层深度清理技术:Display Driver Uninstaller显卡驱动彻底卸载解决方案
  • 2026安防行业监控操作台厂家选购推荐:落地式机柜/一体化机柜/不锈钢操作台厂家/冷通道机柜/四川机柜厂家推荐/选择指南 - 优质品牌商家
  • 零售智能体上线周期缩短至11天,如何复用这3套经GDPR+等保三级认证的Agent模板?
  • Lovable低代码向无代码跃迁的关键阈值:当业务逻辑复杂度>13个条件分支时,必须启用这3个隐藏扩展机制
  • 分布式系统测试:验证分布式系统的正确性和性能
  • React 性能优化:从 3 秒卡顿到 60 帧流畅,我做了这 5 件事
  • 2026优质淋浴房品牌推荐榜适配多元需求:佛山平开门淋浴房/佛山异形淋浴房/佛山扇形淋浴房/佛山淋浴房配件/佛山不锈钢淋浴房/选择指南 - 优质品牌商家
  • 造一个生产级 Flutter WebSocket 客户端:适配器模式 + 七大企业特性全解析
  • 首个「音频-视觉智能」综述:大模型时代的AVI,究竟走到哪一步了?
  • 构建可持续的阅读书源生态:从基础导入到高级管理策略
  • 2026年5月卷帘门定做技术要点及主流厂家盘点:铝合金卷帘门/防盗保温卷帘门/不锈钢卷帘门/保温卷帘门定做/卷帘门品牌/选择指南 - 优质品牌商家
  • 2026年5月新发布:Shiwosi史沃斯以工业级硬实力重塑车间清洁标准 - 2026年企业推荐榜