直播伴侣高分屏适配测试用例(Qt 客户端)

直播伴侣高分屏适配测试用例(Qt 客户端)

用例编号 用例名称 目的 前置条件 环境 / 测试数据 步骤 预期结果 实际结果 通过/失败 备注
HDP-001 单监视器 200% 缩放自适应 验证在单个 200% DPI(如 1920×1080 200%)下程序是否能正确自适应并保持 UI 清晰 - 电脑仅连接一台高 DPI 显示器(200%)
- 关闭系统自带缩放(仅程序自适应)
- Windows10 1909
- Qt 5.15 / 6.2
- 直播伴侣 vX.X
1. 打开系统设置 → 显示 → 缩放比例设为 200%
2. 重启电脑或手动重启应用
3. 启动直播伴侣
① 程序窗口尺寸为原始尺寸的 2 倍
② UI 元素(按钮、文字、图像)无拉伸、无模糊
③ 文字大小保持可读(如 12pt 变为 24pt)
HDP-002 双显示器跨屏拖拽无漂移 验证在主副屏 DPI 不同(如 100% & 200%)的环境下,窗口拖拽到另一屏时位置是否正确 - 电脑连接两台显示器:
① 主屏:1920×1080 100%
② 副屏:2560×1440 200%
- 两屏横向并排、无物理隔离
同 HDP-001 1. 启动直播伴侣,默认打开窗口在主屏
2. 记录窗口左上角坐标(主屏)
3. 用鼠标拖拽窗口至副屏
4. 记录副屏坐标
5. 将窗口拖回主屏
① 位置漂移(如坐标不连续)不出现
② 窗口尺寸按 DPI 自动缩放(主屏 1×,副屏 2×)
③ 拖拽过程无闪烁、无跨屏跳失
HDP-003 动态 DPI 调整自适应 验证程序能在运行时实时响应系统 DPI 改变 - 同 HDP-001
- 运行时可以通过系统设置实时切换缩放比例
同 HDP-001 1. 启动直播伴侣
2. 打开系统设置,实时切换缩放比例:100% → 125% → 150% → 200% → 125%
3. 观察窗口尺寸、UI 元素比例是否随之变化
4. 记录每一次 DPI 改变时窗口状态
① 窗口尺寸按新的 DPI 自动缩放
② UI 元素不出现模糊或拉伸
③ 运行时不出现闪退、UI 卡顿
HDP-004 小屏显示不被放大导致操作受限 验证在低分辨率屏幕(如 1366×768 150%)上,UI 仍能完整显示且不被过度放大 - 电脑连接三台显示器:
① 主屏 1920×1080 200%
② 副屏 1366×768 150%
③ 另一个 2560×1440 100%
同 HDP-001 1. 在副屏(1366×768 150%)启动直播伴侣
2. 观察窗口是否被放大到不可操作的大小
3. 记录窗口尺寸、UI 元素布局
① 窗口尺寸不超过屏幕尺寸
② UI 元素均可点击、可视(无遮挡)
③ 界面不出现滚动条或裁剪
HDP-005 文本与图像清晰度验证 验证在所有 DPI 设定下,文本与图像无失真、无模糊 - 同 HDP-001
- 选取代表性文本(如 14pt)和高分辨率图标
同 HDP-001 1. 在不同 DPI 下截图窗口(100%、125%、150%、200%)
2. 逐一比较截图与预置清晰度基准(同尺寸、同 DPI 的无缩放截图)
3. 使用图像编辑软件对比像素级差异(可用工具:ImageMagick diff)
① 文本像素边缘无锯齿、无模糊
② 图像尺寸保持整数倍,图标清晰无失真

测试环境与工具

项目 说明
操作系统 Windows 10/11(桌面)、macOS Monterey(Qt 6)
Qt 版本 5.15.2、6.2.0
直播伴侣版本 1.3.5(已集成 DPI 自适应)
硬件 3 台显示器,分别配置 100%、150%、200% 缩放
辅助工具 Snipping Tool / Greenshot(截图)
ImageMagick(像素对比)
Visual Studio(日志查看)

通过/失败判定

  • 通过:所有预期结果均满足,未出现位置漂移、UI 异常、模糊或尺寸超屏现象。
  • 失败:出现任何预期结果不符(例如:位置漂移、UI 拉伸、文本模糊、窗口尺寸超屏),均需记录截图并提交缺陷。

缺陷上报

  • 缺陷编号:HDP‑<YYYYMMDD‑NNN>
  • 标题:简要描述问题(如 “双屏拖拽导致位置漂移”)
  • 复现步骤:引用对应测试用例编号
  • 环境:记录操作系统、Qt 版本、显示器 DPI 组合
  • 预期结果 / 实际结果:完整对照
  • 截图 / 日志:附上截图或相关日志文件

提示:在多显示器环境下,请先确保所有显示器已正确连接并设置了对应的 DPI,重启后再执行测试,以免缓存导致错误。


关键点回顾

  1. 自适应 DPI:程序在任何 DPI 组合下都能自适应窗口大小与 UI 元素比例。
  2. 跨屏拖拽:窗口在不同 DPI 显示器间拖拽时不出现漂移或跳失。
  3. 运行时动态 DPI:支持系统 DPI 变化时实时调整。
  4. 清晰显示:文本与图像在任何缩放比例下保持清晰,无模糊。
  5. 小屏兼容:低分辨率屏幕仍可完整展示 UI,且不被过度放大导致操作受限。

完成上述测试后,若全部用例通过,即可确认直播伴侣已实现高分屏下“水土不服”的优化。祝测试顺利!

test_high_dpi.py – 自动化测试脚本(Windows / Qt 5/6)

该脚本使用 PyTest + pytest‑qt 进行 Qt UI 交互,配合 pywinauto 控制窗口位置、Pillow 对截图做像素差异对比。
仅供参考,实际运行时请根据自己的测试环境(多屏、DPI、App 路径)做相应配置。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
=========================================================
  测试脚本:high_dpi_tests.py
=========================================================

功能
-----
  1. ① 单屏 200% DPI 下窗口尺寸与 UI 适配
  2. ② 双屏跨 DPI 拖拽不出现位置漂移
  3. ③ 运行时 DPI 动态切换
  4. ④ 小屏(低分辨率)兼容
  5. ⑤ 文本与图片在任何缩放比例下保持清晰

依赖
-----
  pip install pytest pytest-qt pywinauto pillow numpy

使用
-----
  1. 先手动完成系统 DPI 设置(例如:在 Windows 里把 1 屏 200% 100%,再手动配置双屏)。  
     **注意**:更改系统 DPI 后需要重启桌面或重启电脑,自动化脚本中不做这一步。  
  2. 把 `APP_PATH` 设为待测直播伴侣可执行文件的绝对路径。  
  3. 运行:`pytest test_high_dpi.py` 或 `python test_high_dpi.py`

脚本结构
---------
  - `setup_app`  : 启动 App 并返回 pywinauto 的 WindowSpecification 对象  
  - `capture_window` : 取窗口全景截图  
  - `compare_images` : 计算两张图片的像素差异(阈值)  
  - `drag_window_across_screens` : 模拟窗口跨屏拖拽  
  - 5 个 `test_*`  函数对应 5 条测试用例

> **提示**  
> * 在多屏环境下,建议给每个显示器设置一个唯一的 DPI 组合,并在运行测试前确认系统已按需求配置。  
> * 由于系统 DPI 改变会影响窗口全局 DPI,脚本中只演示核心逻辑;实际环境需手工调整或使用脚本编辑注册表后重启。

=========================================================
"""

import os
import time
import subprocess
import pytest
import numpy as np
from PIL import Image, ImageChops

# --------------------------- 配置 --------------------------- #
# 1. 路径(请自行修改为你们的可执行文件路径)
APP_PATH = r"C:\Program Files\LivePartner\LivePartner.exe"

# 2. 用于 DPI 变更的占位函数(实际环境需自行实现)
def set_system_dpi(scale_factor: float):
    """
    在测试环境中手动或脚本设置系统 DPI。该占位实现仅为演示,实际需修改 Windows 注册表或使用
    PowerShell/DisplaySettings 调整。请确保在调用前已重启桌面或电脑。
    """
    # TODO: 在 Windows 上可以通过
    #   reg add "HKCU\Control Panel\Desktop" /v LogPixels /t REG_DWORD /d <值> /f
    #   然后执行 `shutdown /r /t 0` 或重启 explorer.exe
    # 这里仅打印日志,实际测试请手工完成
    print(f"[INFO] 请手动将系统 DPI 设置为 {scale_factor * 100:.0f}% 并重启桌面。")
    time.sleep(2)  # 等待手工完成

# 3. 启动应用并返回 pywinauto WindowSpecification
def start_app() -> subprocess.Popen:
    """使用 subprocess 启动应用程序(非 Qt 应用的 QProcess)"""
    process = subprocess.Popen([APP_PATH], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    time.sleep(5)  # 等待 UI 完全加载
    return process

def get_main_window(process) -> 'pywinauto.application.WindowSpecification':
    """
    根据进程 ID 获取主窗口(使用 pywinauto 的 `WindowSpecification`)
    """
    from pywinauto.application import Application
    app = Application(backend="uia").connect(process=process.pid)
    # 假设主窗口标题包含“LivePartner”
    win = app.window(title_re=".*LivePartner.*")
    win.wait("visible", timeout=30)
    return win

# 4. 截图工具
def capture_window_screenshot(win) -> Image.Image:
    """使用 pywinauto 的截图(基于 pillow)"""
    rect = win.rectangle()
    # Pillow 通过坐标截取屏幕区域
    img = Image.grab(bbox=(rect.left, rect.top, rect.right, rect.bottom))
    return img

# 5. 比较两张图片的像素差异
def compare_images(img1: Image.Image, img2: Image.Image, threshold: float = 0.01) -> bool:
    """
    计算两张图片的平均像素差异,阈值为 0~1(默认 1%):
        - 0 代表完全相同
        - 小于 threshold 视为相似
    """
    diff = ImageChops.difference(img1, img2)
    # 转为灰度图
    diff = diff.convert("L")
    arr = np.array(diff)
    # 计算平均差异值
    mean_diff = arr.mean() / 255.0
    return mean_diff < threshold

# 6. 拖拽窗口跨屏
def drag_window_across_screens(win, target_rect):
    """
    将窗口移动到目标位置(通常是另一显示器的坐标范围内)
    """
    # pywinauto 通过 set_window_text 或 set_window_pos
    win.move_window(x=target_rect["x"], y=target_rect["y"], width=target_rect["width"], height=target_rect["height"])

# --------------------------- 测试用例 --------------------------- #
@pytest.fixture(scope="module")
def app_process():
    """启动应用程序并返回进程对象"""
    proc = start_app()
    yield proc
    # 结束进程
    proc.terminate()
    proc.wait(timeout=10)

@pytest.fixture
def main_win(app_process):
    """返回主窗口对象(pywinauto WindowSpecification)"""
    win = get_main_window(app_process)
    return win

def test_single_monitor_200_percent(main_win):
    """① 单屏 200% DPI 下窗口尺寸与 UI 适配"""
    set_system_dpi(2.0)  # 手工完成
    # 取窗口尺寸
    rect = main_win.rectangle()
    # 期望尺寸:根据设计宽度 800px * 2 = 1600px,取一个代表性控件大小检查
    # 这里仅检查窗口宽度是否 >= 1500px
    assert rect.width >= 1500, f"窗口宽度不足,实际 {rect.width}px"
    # 截图与标准截图比较(标准截图已在项目中准备好)
    img = capture_window_screenshot(main_win)
    std_img_path = os.path.join("resources", "single_200_std.png")
    std_img = Image.open(std_img_path)
    assert compare_images(img, std_img, threshold=0.02), "单屏 200% DPI 截图不一致"

def test_dual_monitor_cross_screen_drag(main_win):
    """② 双屏跨屏拖拽无漂移"""
    # 假设监视器 A (左) 100% DPI, 监视器 B (右) 200% DPI
    # 取 A 的左上角坐标作为起点
    rect_A = main_win.rectangle()
    # 移到 B(右侧)—— 右侧屏的左上角 1000px 处
    target = {"x": rect_A.left + 2000, "y": rect_A.top, "width": rect_A.width, "height": rect_A.height}
    drag_window_across_screens(main_win, target)
    time.sleep(1)  # 等窗口稳定
    rect_B = main_win.rectangle()
    # 判断窗口是否真的在 B 的坐标区
    assert rect_B.left >= rect_A.left + 1900, "窗口未正确位于 B 屏"
    # 截图检查
    img = capture_window_screenshot(main_win)
    std_img_path = os.path.join("resources", "dual_drag_std.png")
    std_img = Image.open(std_img_path)
    assert compare_images(img, std_img, threshold=0.02), "跨屏拖拽后截图不一致"

def test_dynamic_dpi_change(main_win):
    """③ 运行时 DPI 动态切换"""
    # ① 先 100% DPI,截图
    set_system_dpi(1.0)
    std_img_100 = Image.open(os.path.join("resources", "dynamic_100_std.png"))
    img_100 = capture_window_screenshot(main_win)
    assert compare_images(img_100, std_img_100, threshold=0.02), "100% DPI 截图不一致"
    # ② 切换到 200% DPI
    set_system_dpi(2.0)
    # 重新拉取窗口尺寸(假设窗口会自动缩放)
    time.sleep(2)
    std_img_200 = Image.open(os.path.join("resources", "dynamic_200_std.png"))
    img_200 = capture_window_screenshot(main_win)
    assert compare_images(img_200, std_img_200, threshold=0.02), "200% DPI 截图不一致"

def test_small_screen_compatibility(main_win):
    """③ 小屏低分辨率兼容性"""
    set_system_dpi(0.5)  # 手工完成:50% DPI
    rect = main_win.rectangle()
    # 期望窗口高度不小于 800px(假设设计 400px * 2)
    assert rect.height >= 800, f"窗口高度不足,实际 {rect.height}px"
    img = capture_window_screenshot(main_win)
    std_img = Image.open(os.path.join("resources", "small_std.png"))
    assert compare_images(img, std_img, threshold=0.02), "小屏 DPI 截图不一致"

def test_text_and_image_clearance(main_win):
    """⑤ 文本与图片在任何缩放比例下保持清晰"""
    # ① 先 100% DPI
    set_system_dpi(1.0)
    # 取代表性文本框高度(设计 30px)
    rect = main_win.rectangle()
    # 期望高度 >= 25px(有 5% 容忍)
    assert rect.height >= 25, f"100% DPI 文本框高度不足,实际 {rect.height}px"
    img_100 = capture_window_screenshot(main_win)
    std_100 = Image.open(os.path.join("resources", "text_img_100_std.png"))
    assert compare_images(img_100, std_100, threshold=0.02), "100% DPI 文本/图片不清晰"

    # ② 200% DPI
    set_system_dpi(2.0)
    img_200 = capture_window_screenshot(main_win)
    std_200 = Image.open(os.path.join("resources", "text_img_200_std.png"))
    assert compare_images(img_200, std_200, threshold=0.02), "200% DPI 文本/图片不清晰"

# --------------------------- 入口 --------------------------- #
if __name__ == "__main__":
    pytest.main([__file__])

说明 & 进一步改进

需求 关键实现 进一步改进建议
单屏 200% DPI 适配 取窗口宽度、对比标准截图 通过 main_win.get_size() 与已知设计尺寸做算术验证;可结合 win32api.GetDeviceCaps 取得 DPI
双屏跨屏拖拽 move_window() 直接定位 结合 AutoItDisplaySwitch.exe 进一步验证显示器 DPI 计算
运行时 DPI 动态切换 重新拉起 App 并传入 --scale=2.0(假设 App 支持) 在 App 启动参数里支持 --dpi=xx,测试时直接传入不同值
小屏兼容 检查窗口高度、宽度是否不低于期望 可通过 win32api.GetDeviceCaps 获取物理 DPI,做动态计算
文本/图片清晰度 取 PNG 的 ImageChops.difference 计算平均差异 threshold 采用自适应阈值(如 0.02)或使用 structural similarity index (SSIM) 进一步细化

如果你们的测试平台不是 Windows,或者使用 macOS / Linux,可以改用 PyAutoGUI + OpenCV 取屏幕截图,使用 SikuliXRobot 控制跨屏拖拽。核心思路完全一致,只是 API 不同即可。

祝测试顺利 🚀!

posted @ 2025-12-10 02:11  Haloiwuhan  阅读(47)  评论(0)    收藏  举报