1. 为什么UI自动化测试需要视频录制?
在UI自动化测试中,最令人头疼的问题莫过于那些"幽灵缺陷"——测试脚本明明报告失败,但当你手动复现时却一切正常。这种情况在我们团队每周至少出现3-5次,直到我们引入了视频录制方案才彻底解决。
视频录制能捕获测试执行全过程,相当于给自动化测试装上了"黑匣子"。当测试失败时,你可以:
- 直接观看失败时间点的操作流程
- 观察页面元素的实时状态
- 发现那些只在特定时序下出现的界面闪烁问题
- 确认是脚本逻辑问题还是真实的界面缺陷
我们曾遇到一个经典案例:某个下拉菜单在脚本操作时偶尔无法展开,但手动测试100%正常。通过回放视频发现,问题出在菜单动画尚未完成时脚本就尝试点击,这种时序问题没有视频证据几乎无法排查。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型:为什么是Selenium+FFmpeg?
2.1 Selenium的视频录制方案对比
目前主流的视频录制方案有几种:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Selenium内置截图拼接 | 无需额外依赖 | 帧率低、文件大 | 简单验证 |
| 浏览器插件录制 | 高保真 | 需要手动安装插件 | 单次测试 |
| FFmpeg屏幕捕获 | 灵活可控 | 需要配置参数 | 持续集成 |
| 云测试平台录制 | 开箱即用 | 依赖第三方服务 | 云端执行 |
经过对比,我们选择FFmpeg方案是因为:
- 完全本地化执行,不依赖外部服务
- 可以精确控制录制区域(只捕获浏览器窗口)
- 支持硬件加速,对CI服务器负载小
- 输出文件体积可控(H.264编码)
2.2 FFmpeg的独特优势
FFmpeg作为视频处理领域的"瑞士军刀",在测试录制场景下表现出色:
- 支持多种输入源(屏幕、窗口、虚拟设备)
- 丰富的编码参数调节
- 跨平台兼容(Windows/macOS/Linux)
- 极低的资源占用(实测CPU使用率<5%)
特别是在持续集成环境中,FFmpeg可以:
bash复制ffmpeg -f gdigrab -framerate 30 -offset_x 100 -offset_y 100 -video_size 1280x720 -i title="Chrome" -c:v libx264 -preset ultrafast output.mp4
这条命令实现了:
- 30fps帧率捕获
- 精确定位Chrome窗口
- 硬件加速编码
- 最小化性能影响
3. 完整实现方案
3.1 环境准备
首先确保系统中已安装:
- Python 3.6+
- Selenium最新版
- FFmpeg(加入系统PATH)
- 对应浏览器驱动
推荐使用conda一键配置:
bash复制conda create -n test-recording python=3.8
conda activate test-recording
pip install selenium
conda install -c conda-forge ffmpeg
3.2 核心代码实现
python复制import subprocess
import threading
from selenium import webdriver
from datetime import datetime
class VideoRecorder:
def __init__(self, output_dir="videos"):
self.process = None
self.output_dir = output_dir
os.makedirs(output_dir, exist_ok=True)
def start(self, browser_title):
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
self.output_file = f"{self.output_dir}/{timestamp}.mp4"
# Windows使用gdigrab,Mac使用avfoundation
if sys.platform == "win32":
cmd = [
"ffmpeg", "-f", "gdigrab",
"-framerate", "30",
"-i", f"title={browser_title}",
"-c:v", "libx264",
"-preset", "ultrafast",
self.output_file
]
else:
cmd = [
"ffmpeg", "-f", "avfoundation",
"-capture_cursor", "1",
"-i", "1",
"-c:v", "libx264",
"-preset", "fast",
self.output_file
]
self.process = subprocess.Popen(
cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
def stop(self):
if self.process:
self.process.communicate(input=b'q')
self.process.wait()
# 在测试用例中的使用示例
def test_login():
recorder = VideoRecorder()
driver = webdriver.Chrome()
try:
recorder.start(driver.title)
driver.get("https://example.com/login")
# ...执行测试步骤...
finally:
recorder.stop()
driver.quit()
3.3 关键参数调优
根据我们的实战经验,这些参数最影响录制效果:
-
帧率选择:
- 功能测试:15fps足够
- 动画验证:需要30fps
- 性能测试:可降至5fps
-
编码预设:
python复制"-preset", "ultrafast" # 最低CPU消耗,但文件较大 "-preset", "medium" # 平衡选择 -
分辨率控制:
python复制"-video_size", "1280x720" # 高清足够 -
关键帧间隔:
python复制"-g", "300" # 每300帧一个关键帧
4. 实战中的六大陷阱与解决方案
4.1 窗口定位失败
现象:FFmpeg报错"Can't find window title"
解决方案:
python复制# 先确保浏览器窗口有唯一标题
driver.execute_script("document.title='AUT_' + Date.now();")
# 或者使用窗口句柄
hwnd = driver.current_window_handle
# Windows下通过pywin32获取窗口坐标
4.2 视频不同步
现象:操作与视频有1-2秒延迟
优化方案:
- 增加时间戳覆盖
python复制# 在关键步骤添加屏幕文字 driver.execute_script(f""" var overlay = document.createElement('div'); overlay.style.position = 'fixed'; overlay.innerHTML = '{datetime.now().isoformat()}'; document.body.appendChild(overlay); """)
4.3 CI环境无显示器
解决方案:
- 使用虚拟帧缓冲区
bash复制# Linux Xvfb :99 -screen 0 1920x1080x24 & export DISPLAY=:99 # Windows Set-Service umrd -StartupType Automatic Start-Service umrd
4.4 大文件处理
优化技巧:
- 分段录制
python复制# 每10分钟创建一个新文件 if time.time() - start_time > 600: recorder.stop() recorder.start(driver.title) - 自动删除旧文件
python复制# 保留最近20个视频 videos = sorted(glob.glob("videos/*.mp4")) for old in videos[:-20]: os.remove(old)
4.5 元素高亮辅助
增强视频可读性:
python复制def highlight(element, duration=3):
original_style = element.get_attribute("style")
driver.execute_script(
"arguments[0].style.border='3px solid red';",
element
)
time.sleep(duration)
driver.execute_script(
f"arguments[0].style='{original_style}';",
element
)
4.6 跨平台兼容
处理不同OS的差异:
python复制class VideoRecorder:
def get_screen_cmd(self):
if sys.platform == "win32":
return ["ffmpeg", "-f", "gdigrab", ...]
elif sys.platform == "darwin":
return ["ffmpeg", "-f", "avfoundation", ...]
else:
return ["ffmpeg", "-f", "x11grab", ...]
5. 进阶集成方案
5.1 与Allure报告结合
在测试报告中嵌入视频:
python复制# conftest.py
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
report = outcome.get_result()
if report.when == 'call' and hasattr(item, 'recorder'):
allure.attach.file(
item.recorder.output_file,
name="execution_video",
attachment_type=allure.attachment_type.MP4
)
5.2 智能失败分析
自动标记关键片段:
python复制def test_checkout():
recorder = VideoRecorder()
markers = []
try:
recorder.start()
markers.append(("start", time.time()))
# 操作步骤...
markers.append(("add_to_cart", time.time()))
# 更多操作...
except Exception as e:
markers.append(("error", time.time()))
raise
finally:
recorder.stop()
generate_highlight_reel(markers) # 生成带标记点的视频
5.3 视频元数据注入
记录测试上下文:
python复制def add_metadata(filename, test_name, status):
subprocess.run([
"ffmpeg", "-i", filename,
"-metadata", f"test_name={test_name}",
"-metadata", f"test_status={status}",
"-codec", "copy",
f"with_meta_{filename}"
])
6. 性能优化实战
经过3个月的持续优化,我们的视频录制方案达到了:
- 平均CPU占用:<8%
- 内存消耗:~50MB
- 视频文件大小:1分钟约5MB
- 延迟:<500ms
关键优化点:
-
硬件加速编码:
python复制"-c:v", "h264_nvenc" # NVIDIA显卡 "-c:v", "h264_qsv" # Intel核显 -
智能帧率调节:
python复制# 根据操作类型动态调整 if is_animation_heavy: frame_rate = 30 else: frame_rate = 10 -
区域更新检测:
bash复制
ffmpeg -f gdigrab -draw_mouse 0 -show_region 1 ...
这套方案已在我们的CI流水线稳定运行半年,帮助定位了200+个时序相关缺陷,测试失败排查时间从平均45分钟缩短到5分钟以内。特别是在Flaky测试分析方面,视频证据让我们发现了15%的测试失败其实是环境问题而非代码缺陷。
