3. 测试环境搭建:硬件环境、软件环境与自动化框架选型
做固件升级稳定性测试,环境搭建是地基。地基没打好,后面跑出来的数据全是废的。我见过太多团队,一上来就急着写用例,结果环境里电源不稳、网络丢包、日志不全,折腾两周连一次完整的升级流程都跑不通。
这一章,我把环境拆成三块来讲:硬件、软件、自动化框架。每块都有我踩过的坑,你照着搭,至少能省一半的调试时间。
3.1 硬件环境:设备、电源、网络
硬件环境的核心就三个字:可控。你不能让被测设备在不可控的条件下跑测试,否则出了问题你根本分不清是固件 bug 还是环境干扰。
3.1.1 被测设备
设备选型上,我建议你准备至少三台同型号设备。为什么是三台?
- 一台跑正常流程:用来做基准对比,确保测试环境本身没问题。
- 一台跑异常流程:断电、断网、强制重启,这台就是用来折腾的。
- 一台备用:万一刷成砖了,不用等维修,直接换上去继续跑。
另外,设备上的串口一定要引出来。我习惯用 USB 转 TTL 模块,焊在板子的调试口上。这样即使设备死机、网络不通,我还能通过串口看最后一条日志,知道它死在哪一步。
3.1.2 电源
电源是很多人忽略的坑。你以为市电很稳?其实不是。工厂车间、实验室里,大功率设备一启动,电压瞬间能掉十几伏。
我的做法是这样的:
- 用可编程直流电源,比如 ITECH 或 Rigol 的。可以设置电压、电流上限,还能记录电压波动曲线。
- 模拟电压跌落:设置电源在升级过程中突然从 12V 降到 9V,持续 2 秒再恢复。看看设备会不会重启、升级会不会中断。
- 模拟掉电:用继电器控制电源通断,在升级的不同阶段(擦写 flash 时、校验时、重启时)随机断电。
3.1.3 网络
网络环境要模拟真实场景。你不能只在千兆局域网里测,用户家里可能是 2.4G Wi-Fi,信号差、延迟高、偶尔丢包。
我推荐用 网络损伤仪,比如 Spirent 或 iTrinegy 的。如果预算有限,也可以用 Linux 的 tc 命令模拟。
下面是我常用的网络损伤参数:
| 场景 | 延迟 | 丢包率 | 带宽限制 | 抖动 |
|---|---|---|---|---|
| 理想局域网 | < 1ms | 0% | 1000 Mbps | 0ms |
| 普通家庭 Wi-Fi | 10-30ms | 0.5% | 50 Mbps | 5ms |
| 弱信号 Wi-Fi | 50-150ms | 2% | 10 Mbps | 20ms |
| 移动网络(4G) | 30-80ms | 1% | 20 Mbps | 10ms |
用 tc 模拟弱信号 Wi-Fi 的示例:
# 添加延迟 100ms,抖动 20ms,丢包 2%
tc qdisc add dev eth0 root netem delay 100ms 20ms loss 2%
# 限制带宽 10Mbps
tc qdisc add dev eth0 root tbf rate 10mbit burst 32kbit latency 400ms
3.2 软件环境:升级服务器、日志工具、抓包工具
软件环境决定了你能不能看清问题。我常说一句话:日志不全,等于没测。
3.2.1 升级服务器
升级服务器要能模拟各种异常响应。你不能只测正常流程,还要测服务器返回 404、500、超时、数据损坏等情况。
我习惯用 Python Flask 或 Node.js Express 搭一个轻量级升级服务器。代码量不大,但控制力很强。
下面是一个简单的 Flask 升级服务器示例,支持模拟各种异常:
from flask import Flask, send_file, abort, request
import time
import random
app = Flask(__name__)
@app.route('/upgrade/firmware.bin', methods=['GET'])
def upgrade():
# 模拟网络延迟
delay = request.args.get('delay', '0')
time.sleep(float(delay))
# 模拟随机失败
if random.random() < 0.05: # 5% 概率返回 500
abort(500)
# 模拟数据损坏(返回随机字节)
if request.args.get('corrupt') == '1':
return bytes([random.randint(0, 255) for _ in range(1024*1024)])
# 正常返回固件文件
return send_file('firmware.bin', mimetype='application/octet-stream')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
3.2.2 日志工具
日志工具要解决两个问题:集中收集和实时分析。
我推荐用 ELK Stack(Elasticsearch + Logstash + Kibana)或者轻量级的 Loki + Grafana。如果设备数量不多,用 rsyslog 集中转发也行。
设备端日志格式要统一,我建议用 JSON 格式,方便解析:
{
"timestamp": "2025-03-15T10:30:00.123Z",
"device_id": "SN-20250315-001",
"module": "ota_upgrade",
"level": "ERROR",
"message": "Flash write failed at offset 0x1000",
"extra": {
"retry_count": 3,
"current_version": "v2.1.0",
"target_version": "v2.2.0"
}
}
日志级别我建议分四级:INFO(正常流程)、WARN(重试、超时)、ERROR(失败)、FATAL(设备死机)。这样在 Kibana 里一搜 level: ERROR 就能快速定位问题。
3.2.3 抓包工具
抓包工具用来分析网络协议层面的问题。我主要用 Wireshark 和 tcpdump。
抓包时要注意:
- 只抓升级相关的端口,避免数据量太大。比如升级服务器端口是 8080,就只抓
port 8080。 - 保存完整的 pcap 文件,不要只抓前几秒。有些问题发生在升级快结束时,比如最后的 ACK 丢了。
- 用 tshark 做自动化分析,比如统计重传率、RTT 变化。
抓包命令示例:
# 只抓升级服务器的流量,保存到文件
tcpdump -i eth0 -w upgrade_test.pcap port 8080
# 用 tshark 统计重传包数量
tshark -r upgrade_test.pcap -Y "tcp.analysis.retransmission" | wc -l
3.3 自动化测试框架选型
手动测升级?一次两次还行,跑 1000 次你肯定崩溃。自动化是必须的。
选框架时,我主要看三点:设备控制能力、日志集成能力、报告生成能力。
3.3.1 主流框架对比
| 框架 | 适用场景 | 设备控制 | 日志集成 | 学习成本 | 我推荐吗? |
|---|---|---|---|---|---|
| pytest + paramiko | Linux 设备、SSH 连接 | 强(SSH/串口) | 中(需自行集成) | 低 | ✅ 推荐 |
| Robot Framework | 关键字驱动、非技术人员 | 中(需写库) | 强(内置报告) | 中 | ✅ 推荐 |
| Appium | Android/iOS 设备 | 强(ADB/XCUITest) | 中 | 高 | ⚠️ 仅移动端 |
| Jenkins Pipeline | CI/CD 集成 | 弱(需脚本配合) | 强(插件丰富) | 中 | ⚠️ 适合调度 |
| 自研框架 | 特殊协议、私有接口 | 最强 | 自定义 | 高 | ⚠️ 最后选择 |
我个人最常用的是 pytest + paramiko。原因很简单:Python 生态成熟,paramiko 能直接通过 SSH 控制设备,pytest 的 fixture 机制很适合做升级前后的状态管理。
3.3.2 我的推荐组合
如果你现在要从零搭建,我建议这样选:
- 测试框架:pytest(灵活、插件多)
- 设备控制:paramiko(SSH)+ pyserial(串口)
- 日志收集:ELK 或 Loki + Grafana
- 网络模拟:tc 命令或网络损伤仪
- 报告生成:pytest-html 或 Allure
- 持续集成:Jenkins 或 GitLab CI
3.4 整体环境架构图
下面这张图是我搭建升级测试环境的整体架构。你可以照着这个结构来规划自己的环境。
这张图里,自动化测试控制机是大脑,它通过 SSH 控制设备、通过串口收日志、通过继电器控制电源、通过 tc 命令调整网络。所有测试用例都在控制机上跑,结果统一汇总到 ELK 或 Grafana 展示。