第三章 测试环境搭建:硬件准备与软件工具

做机顶盒稳定性测试,环境搭建是第一步,也是最容易被忽视的一步。我见过太多团队,上来就写测试用例,结果跑了两天发现日志没抓到,或者设备死机了没法重启——嗯,那叫一个尴尬。

今天咱们就把这套环境拆开揉碎了讲。说白了,就是三块:硬件怎么连、软件用什么、自动化怎么搭

3.1 硬件准备:别让物理层卡住你

硬件准备这块,我个人的习惯是「宁可多接一根线,不要少留一个口」。你想想看,测试跑到半夜,设备死机了,你人不在现场,这时候全靠硬件撑着。

3.1.1 串口线:调试的生命线

串口线是嵌入式调试的「最后一道防线」。为什么这么说?因为当系统内核崩溃、网络断连、HDMI无输出时,串口往往是唯一还能跟你对话的通道。

我在项目中遇到过最典型的情况:机顶盒跑压力测试,跑着跑着画面卡死了。ADB连不上,网络也断了。幸好串口线接着,我一看日志,是内存泄漏导致OOM killer把关键进程杀了。

串口接线要点:

  • 使用USB转TTL模块(推荐FT232或CH340),别用那些杂牌,丢数据丢到你怀疑人生
  • 接线:GND接GND,TX接RX,RX接TX——这个顺序我每次都要默念一遍
  • 波特率通常用115200,但有些老平台用38400,记得查芯片手册

我曾经踩过的坑: 有一次串口线太长(超过3米),信号衰减导致乱码。后来换成带屏蔽的线,问题解决。串口线建议控制在1.5米以内。

3.1.2 HDMI采集卡:让画面可追溯

稳定性测试中,画面异常(花屏、黑屏、闪屏)是最直观的故障表现。但人眼盯着屏幕看8小时?不现实。这时候就需要HDMI采集卡。

我建议用USB接口的采集卡,比如圆刚或时立的,支持1080P@60fps就够了。4K采集卡太贵,而且机顶盒大部分场景还是1080P输出。

采集卡参数 推荐规格 说明
分辨率 1080P@60fps 覆盖绝大多数机顶盒输出
接口 USB 3.0 USB 2.0带宽不够,会掉帧
延迟 < 100ms 用于自动化比对时延迟越低越好

小技巧: 采集卡配合OpenCV做画面比对,可以自动检测花屏。我写过一段脚本,每隔5秒截一帧,跟参考帧做PSNR计算,低于阈值就报警。

3.1.3 电源监控:别让供电背锅

很多稳定性问题,查到最后发现是电源纹波太大。所以电源监控不是可选项,是必选项。

我常用的方案是:USB电流电压表 + 可编程电源。USB表实时监控电流电压,可编程电源用来模拟异常供电(比如电压跌落、瞬间断电)。

举个例子:测试待机唤醒稳定性时,我会让可编程电源在待机状态下把电压从5V降到4.5V,看看机顶盒还能不能正常唤醒。这种场景在实际用户家里很常见——老旧插座接触不良。

3.2 软件工具:趁手的兵器

硬件搭好了,软件工具就是你的「眼睛」和「手」。我习惯把工具分成三类:连接工具、调试工具、日志工具。

3.2.1 ADB:Android调试桥

现在的机顶盒大部分是Android系统,ADB是标配。但很多人只用adb shell和adb install,其实ADB能干的事多着呢。

# 常用ADB命令
adb devices                    # 查看设备列表
adb logcat -b all -v time      # 抓取所有日志,带时间戳
adb shell dumpsys meminfo      # 查看内存使用
adb shell top -n 1             # 查看CPU占用
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED  # 模拟开机广播

我个人的习惯: 写一个adb_wrapper.sh脚本,把常用命令封装成函数。比如 adb_mem 自动抓取内存快照,adb_log 自动过滤关键错误。这样测试脚本里调用起来特别顺手。

3.2.2 串口终端:PuTTY与Minicom

Windows下我用PuTTY,Linux下用Minicom。但说实话,这两个工具都「能用,但不好用」。我后来换成了MobaXterm,支持多标签、日志自动保存、颜色高亮,省心不少。

串口终端的关键配置:

  • 本地回显关闭(否则你打字会看到重复字符)
  • 日志自动保存到文件(万一出问题,翻日志用)
  • 设置行缓冲区大小(我设成5000行,太少的话关键信息被冲掉)

注意: 串口日志默认是ASCII编码,如果机顶盒输出中文日志,记得把终端编码改成UTF-8。我曾经因为编码问题,排查了半天才发现日志里的中文错误信息全是乱码。

3.2.3 日志抓取工具:logcat与dmesg

日志是稳定性测试的「黑匣子」。没有日志,出了问题你只能靠猜。

我一般同时抓三路日志:

  1. logcat:Android应用层日志,关注ANR、Crash、Service异常
  2. dmesg:内核日志,关注驱动报错、内存不足、文件系统错误
  3. 串口日志:bootloader和kernel启动阶段的日志,有时候系统还没跑起来logcat还没启动,串口日志就是唯一的线索
# 自动化日志抓取脚本片段
import subprocess
import threading

def start_logging():
    # logcat
    t1 = threading.Thread(target=lambda: subprocess.run(
        ['adb', 'logcat', '-v', 'time', '-f', '/data/logs/app.log']))
    # dmesg
    t2 = threading.Thread(target=lambda: subprocess.run(
        ['adb', 'shell', 'dmesg', '-w', '>', 'kernel.log']))
    t1.start()
    t2.start()

3.3 自动化测试框架:Python + pytest

手动测试跑一轮还行,跑100轮?你手会断。所以自动化是必须的。我选Python + pytest,原因很简单:生态好、社区大、遇到问题搜一下就有答案。

3.3.1 框架结构设计

我的测试框架一般分三层:

  • 底层:设备控制层(ADB封装、串口封装、采集卡控制)
  • 中间层:测试用例层(pytest的test_函数)
  • 上层:报告与告警层(生成HTML报告、发送钉钉/邮件通知)
# 一个简单的pytest测试用例
import pytest
import subprocess

class TestSystemStability:
    
    def test_reboot_100_times(self):
        """反复重启100次,检查系统是否稳定"""
        for i in range(100):
            # 执行重启
            subprocess.run(['adb', 'reboot'])
            # 等待设备重新上线
            assert wait_for_device(timeout=120), f"第{i+1}次重启后设备未上线"
            # 检查关键进程
            assert check_process('surfaceflinger'), "surfaceflinger进程异常"
            # 检查日志有无Fatal
            assert not check_log_for_fatal(), "日志中发现Fatal错误"
            
        print("100次重启测试通过")

经验之谈: 测试用例里一定要加超时控制。我见过一个同事写的脚本没有超时,设备死机后脚本一直卡在wait_for_device那里,跑了一整夜都没出结果。后来我统一加了timeout参数,超过时间就标记为FAIL并自动重启设备继续下一轮。

3.3.2 测试报告与数据可视化

跑完测试,结果要能看得懂。我习惯用pytest-html插件生成报告,再配合Grafana做实时监控面板。

报告里必须包含:

  • 测试通过/失败总数
  • 失败用例的详细日志(时间戳、错误信息、截图)
  • 性能趋势图(内存占用、CPU使用率随时间变化)

嗯,说到报告,我最近在做一个改进:把每次测试的串口日志自动截取关键片段,附在报告里。这样排查问题时不用再去翻几十MB的原始日志。

3.4 环境验证:搭好了先跑一圈

环境搭完别急着写用例。先跑一个「冒烟测试」,验证所有链路是否通畅:

  1. 串口能正常收发数据吗?
  2. ADB能连上并执行命令吗?
  3. 采集卡能正常采集画面吗?
  4. 电源监控能记录电压曲线吗?
  5. 自动化脚本能完整跑完一个用例吗?

这五步走完,你的测试环境才算真正「就绪」。我见过太多人跳过这步,结果正式测试第一天就发现串口线没接好——白白浪费一整天。

总结一句话: 测试环境搭建不是一次性工作,而是持续优化的过程。每次遇到新问题,我都会反思:是不是环境层面可以提前发现?比如加个电压监控、多抓一路日志。慢慢地,你的环境就会越来越「抗造」。

下一章咱们聊聊具体的测试用例设计——怎么写出既能发现问题、又不会把测试机跑废的用例。