跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Python大前端

基于 Python 的 Web 与 App 端自动化测试实践

基于 Python 的 Web 与 App 端自动化测试涉及环境搭建、PO 模式封装、Fixture 管理及跨端交互验证。通过 Playwright 和 Appium 实现配置生效检查、图片哈希比对及坐标滑动操作,解决元素定位与截图校验问题。

数字游民发布于 2026/4/8更新于 2026/10/2298 浏览

引言

本文介绍在 Web 端修改客户端配置后,验证客户端查看配置是否生效的自动化测试实现方案。

一、测试环境

  1. 代码编辑器使用 PyCharm,编程语言选择 Python。
  2. Web 自动化测试工具选择 Python 第三方库 Playwright,客户端测试工具选择 Appium。
  3. 项目架构:Web 端 + App 端。
  4. 测试用例管理方法:Pytest。
  5. Python 及第三方库版本:Python 3.11, Playwright 1.57.0, Pytest 8.3.3, Selenium 4.33, appium-python-client 5.1.1。
  6. Appium Server: v2.18.0。

二、项目结构

1. PyCharm 文件脚本目录

  1. tests: 新建 Python 软件包用于存放测试文件。用 Pytest 整合测试用例,所以测试文件以 test_ 开头,例如 test_patient_screen.py。
  2. setting: 用来存放测试中用到的配置信息,如 Web 端登录的用户名密码、要上传的文件、延时时间等。放在 setting 下面方便自定义配置后期维护,且 Python 导入时能自动查找。
  3. pages: 使用 PO 模式进行 Web 端测试时会用到。PO 模式是将本次测试中经常用到的界面操作根据当前页面来封装。例如数据查询页面包含输入关键词、点击搜索、翻页、拉动进度条等操作,将这些操作封装成一个类,下次切换到该界面时直接调用类中的操作函数。
  4. log: 存放日志。当有多个测试用例时,用日志记录操作步骤和捕获错误是个好办法。工具是 Python 的 logging 库。

2. 关键对象与 Fixture

  1. Browser 规划生成器的生命范围。
@pytest.fixture(scope="session")
def browser() -> Browser:
    playwright = sync_playwright().start()
    browser = playwright.chromium.launch(headless=False, slow_mo=30000)
    yield browser
    browser.close()
    playwright.stop()
  1. Page
@pytest.fixture(scope="class")
def page(browser: Browser) -> Page:
    context = browser.new_context()
    page = context.new_page()
    yield page
    page.close()
    context.close()

装饰器说明 page 生成器的生命范围是 class,所以在第一次调用此生成器的测试类中 page 是可以延续的。即第一个测试用例可能需要先进行登录操作,后续的测试函数直接从上一个测试结束时的界面状态开始。

  1. 控制 App 的 Driver scope="class",Appium 控制设备在第一次调用 driver 的 class 中是连续的,执行完第一个测试用例后在执行第二个之前不会重启 App。
@pytest.fixture(scope='class')
def create_driver():
    desired_cap = {
        "platformName": "Android",
        "platformVersion": "6",  # 建议移除,除非必要,Appium 会自动检测
        "deviceName": "设备名称",  # 可改为通用名称
        "udid": "udid",          # 关键:使用 udid 指定你的设备
        "appPackage": "app 名",
        "appActivity": "初始化界面 app 活动名",
        "automationName": "UiAutomator2",
        "noReset": True,
        "newCommandTimeout": 900,
        "autoGrantPermissions": True,
        "unicodeKeyboard": True,
        "resetKeyboard": True
    }
    options = AppiumOptions()
    options.load_capabilities(desired_cap)
    driver = None
    try:
        driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", options=options)
        driver.implicitly_wait(30)
        print("驱动初始化成功,设备已连接")
        yield driver  # 将 driver 提供给外部使用
    finally:
        if driver:
            driver.quit()
            print("驱动已关闭")
  1. 日志生成器 调用 logging 模块后声明日志工具。
@pytest.fixture(scope="session")
def logger():
    logger = logging.getLogger("日志")
    logger.setLevel("DEBUG")
    log_dir = "./log"
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)
    log_file = os.path.join(log_dir, 'log.txt')
    log_handler = logging.handlers.RotatingFileHandler(log_file, mode='w', encoding='utf-8')
    log_format = "%(asctime)s-%(levelname)s-%(process)d-%(message)s"
    fmt = logging.Formatter(fmt=log_format)
    log_handler.setFormatter(fmt)
    logger.addHandler(log_handler)
    yield logger
    print("销毁日志记录器")

有了这个日志工具后,在测试用例文件中要打印什么直接 logger.info("") 或者 logger.error("")。

三、PO 模式具体使用

在 pages 软件包中添加 py 文件 login.py。

from playwright.sync_api import Page

class PatientScreen:
    def __init__(self, page: Page):
        self.page = page

    def navigate(self):
        self.page.get_by_text()
        self.page.get_by_role()
        # ... 其他操作

类 PatientScreen 是封装的一个页面,__init__ 方法中声明此类的属性 page。

关于这个页面下的操作如何写,推荐使用 Playwright 自带的 codegen 录制工具,能自动生成操作相应的代码。

playwright codegen "http://..."

在测试文件 py 中如何调用呢?

class TestPatientScreen:
    def test_template_color(self, page, create_driver, logger):
        logger.info("case1: 测试一览表背景颜色切换")
        login_page = WebLogin(page)
        patientscreen_page = PatientScreen(page)

声明测试类后,在测试函数中可以直接调用在 common 中声明的生成器 page,然后声明一个 PO 模式中类的对象作为我们要操作的对象。例如 login_page 是登录界面的可以执行类中动作的对象。

四、Appium 定位元素的新方法总结

  1. 跨端图片比对 遇到一个在 Web 端上传图片后验证 App 端是否正确上传了的测试点。先获取设备上的图片:
logo = create_driver.find_element(By.XPATH, '/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.FrameLayout[1]/android.widget.LinearLayout/android.widget.ImageView')
screenshot_bytes = logo.screenshot_as_png
with open(device_logo_path, "wb") as f:
    f.write(screenshot_bytes)

然后再把原图保存在工程的一个位置(建议保存在 setting 下面),比较图片是否是同一张的方法:计算汉明距离。

from PIL import Image
import imagehash

def hash_compare(img1_path, img2_path, threshold=16):
    hash1 = imagehash.phash(Image.open(img1_path))
    hash2 = imagehash.phash(Image.open(img2_path))
    hamming_distance = int(hash1) - int(hash2)
    is_similar = hamming_distance <= threshold
    if is_similar:
        print("同一张图片")
    else:
        print("不是同一张")

threshold 是比较的严格程度,越小越严格,最大 64。根据经验,两张完全不同的图片选择 64 会被判断为一样,取 16 可以分辨不同的图片,所以最终选了 16。

  1. 坐标滑动 Web 端开启手动滑动功能,远程工具连接设备,鼠标确实能拖动小窗口上下滑动,但是通过 Appium 定位不到这个可滑动的元素。于是采用坐标滑动的方法。
def swipe_up(driver, start_x_percent=0.2, start_y_percent=0.8, end_y_percent=0.2):
    width = driver.get_window_size()['width']
    height = driver.get_window_size()['height']
    actions = ActionChains(driver)
    actions.w3c_actions = ActionBuilder(driver, mouse=PointerInput(interaction.POINTER_TOUCH, "TOUCH"))
    actions.w3c_actions.pointer_action.move_to_location(start_x_percent * width, start_y_percent * height)
    actions.w3c_actions.pointer_action.pointer_down()
    actions.w3c_actions.pointer_action.move_to_location(start_x_percent * width, end_y_percent * height)
    actions.w3c_actions.pointer_action.pointer_up()
    actions.perform()

注:之前的 swipe 方法简单又快捷,但现在好像只支持 ActionChains 这种方法。

目录

  1. 引言
  2. 一、测试环境
  3. 二、项目结构
  4. 1. PyCharm 文件脚本目录
  5. 2. 关键对象与 Fixture
  6. 三、PO 模式具体使用
  7. 四、Appium 定位元素的新方法总结

更多推荐文章

查看全部
  • 零基础入门网络安全:3 个月学习路线与资源指南
  • Python FastAPI 入门实战:从环境搭建到核心功能详解
  • 千笔 AI:辅助学术写作的智能工具
  • 飞算 JavaAI 智能代码治理与重构实践
  • C++ 类的基础概念与实战指南
  • 基于学习的机器人变阻抗控制实现轴孔装配任务
  • AI 大模型本地部署指南:使用 Ollama 快速运行
  • 网络运维与网络安全运维的区别及就业前景分析
  • 拆解 CASIC MOTOR 机器人底盘无刷减速电机
  • Miniforge 离线安装指南:无网络环境下的 Python 部署方案
  • 3D Gaussian Splatting 动态场景应用:从 SLAM 到虚拟现实
  • Python 零基础入门到进阶学习路径详解
  • Android Studio 配置 Gradle 国内镜像地址
  • GLM-5 开源发布:7440 亿参数智能体模型
  • 基于 Pandas 与 Pyecharts 的全国星巴克门店数据可视化分析
  • 千笔 AI 辅助论文写作工具核心功能介绍
  • DeepSeek 浪潮下,前端开发的变革与实战指南
  • STM32F0 系列 FOC 开源算法源码解析:观测器与电流采样
  • ChatGPT 降低毕业论文 AIGC 重复率方法指南
  • MCP Server 案例:Excel 表格一键生成可视化图表 HTML 报告

相关免费在线工具

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online