4. 测试自动化框架选型:Python unittest、pytest、Robot Framework、Selenium对比
做硬件测试的兄弟,一听到「自动化框架」四个字,第一反应往往是:「那是软件测试的事吧?」
嗯,我以前也这么想。直到有一次,我负责一个智能硬件的量产项目,每天要手动跑2000次固件升级测试,手指头都快按断了。从那天起,我彻底明白了——硬件测试的自动化,不是可选项,是必选项。
今天咱们就来聊聊,市面上最常用的四个Python生态测试框架:unittest、pytest、Robot Framework、Selenium。注意,Selenium虽然主打Web自动化,但在硬件测试里,它经常被用来做嵌入式Web管理页面的交互测试,所以也拉进来一起对比。
4.1 先看底层逻辑:你究竟需要什么?
选框架之前,我建议你先问自己三个问题:
- 谁来写测试? 是纯硬件工程师,还是软硬兼修的测试开发?
- 被测对象是什么? 是命令行接口、串口协议、还是Web管理页面?
- 测试报告给谁看? 老板要看高大上的HTML报告,还是你自己看log就行?
这三个问题决定了你的选型方向。别一上来就追新框架,我见过太多团队,框架换了三四个,测试用例一个没写出来。
4.2 Python unittest:老牌正统,但有点「重」
unittest是Python标准库自带的,不用装任何第三方包。它的设计思路模仿了Java的JUnit,非常规整。
举个例子,你要测试一个电源模块的电压输出:
import unittest
import serial
class TestPowerModule(unittest.TestCase):
def setUp(self):
# 每次测试前,打开串口连接
self.ser = serial.Serial('COM3', 115200, timeout=1)
def tearDown(self):
self.ser.close()
def test_output_voltage_12v(self):
self.ser.write(b'MEAS:VOLT?\n')
voltage = float(self.ser.readline().strip())
self.assertAlmostEqual(voltage, 12.0, delta=0.1)
def test_output_voltage_5v(self):
self.ser.write(b'MEAS:VOLT:5V?\n')
voltage = float(self.ser.readline().strip())
self.assertAlmostEqual(voltage, 5.0, delta=0.05)
if __name__ == '__main__':
unittest.main()
我个人习惯用unittest做底层库的单元测试,比如写一个I2C驱动库,用unittest跑一遍,心里踏实。但说实话,它的缺点也很明显:样板代码太多。每个测试类都要写setUp和tearDown,测试数据驱动也不够灵活。
parameterized库来做参数化测试,能省不少代码量。
4.3 pytest:我目前的主力框架
如果让我只推荐一个框架,那就是pytest。它比unittest简洁太多,而且插件生态极其丰富。
同样的电源模块测试,用pytest写出来是这样的:
import pytest
import serial
@pytest.fixture
def serial_conn():
"""串口连接夹具,自动管理资源"""
ser = serial.Serial('COM3', 115200, timeout=1)
yield ser
ser.close()
def test_output_voltage_12v(serial_conn):
serial_conn.write(b'MEAS:VOLT?\n')
voltage = float(serial_conn.readline().strip())
assert abs(voltage - 12.0) < 0.1
def test_output_voltage_5v(serial_conn):
serial_conn.write(b'MEAS:VOLT:5V?\n')
voltage = float(serial_conn.readline().strip())
assert abs(voltage - 5.0) < 0.05
看到了吗?没有类,没有self,直接用函数。fixture机制比setUp/tearDown灵活太多了。我在项目中遇到过最头疼的问题——测试用例之间共享硬件资源,用pytest的scope="module"或scope="session"轻松搞定。
- 插件丰富:
pytest-html生成报告,pytest-xdist并行执行,pytest-rerunfailures失败重跑 - fixture机制: 完美管理仪器连接、串口、GPIO等硬件资源
- 参数化: 一行代码搞定多组测试数据
- 断言直观: 直接用Python的
assert,不用记一堆assertEqual
yield之后的清理代码,结果跑完1000个用例,仪器连接数爆了。记住:有借有还,再借不难。
4.4 Robot Framework:关键字驱动的「傻瓜相机」
Robot Framework是个另类。它不要求你写Python代码,而是用「关键字」来描述测试步骤。说白了,它把测试用例变成了「填表格」。
同样的电源测试,用Robot Framework写出来是这样的:
*** Settings ***
Library SerialLibrary
*** Test Cases ***
测量12V输出电压
[Setup] Open Serial Port COM3 115200
Write Data MEAS:VOLT?\n
${voltage}= Read Until \n
Should Be Equal As Numbers ${voltage} 12.0 delta=0.1
[Teardown] Close Serial Port
这个框架最大的优势是:测试用例可读性极强。不懂编程的硬件工程师、产线技术员,都能看懂甚至编写用例。我在一个代工厂的项目里用过Robot Framework,产线上的兄弟培训了半小时就能上手改测试参数了。
但它的缺点也很致命:调试困难。一旦出问题,你很难定位是关键字库的bug还是测试逻辑的问题。而且,如果你要做复杂的条件判断、循环、数据处理,Robot Framework会变得非常别扭。
4.5 Selenium:硬件测试里的「跨界选手」
Selenium是Web自动化测试的标配,但为什么硬件测试也要聊它?
因为现在越来越多的嵌入式设备,都带了一个Web管理页面。路由器、智能网关、工业控制器……你想想看,这些设备的配置界面,本质上就是个Web应用。你要测试「修改WiFi密码后设备是否正常重启」,用Selenium模拟浏览器操作,比用串口发AT指令靠谱多了。
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
def test_wifi_reconnect():
driver = webdriver.Chrome()
driver.get("http://192.168.1.1")
# 登录
driver.find_element(By.ID, "username").send_keys("admin")
driver.find_element(By.ID, "password").send_keys("admin123")
driver.find_element(By.ID, "login-btn").click()
time.sleep(2)
# 修改WiFi密码
driver.find_element(By.LINK_TEXT, "无线设置").click()
driver.find_element(By.ID, "wifi_password").clear()
driver.find_element(By.ID, "wifi_password").send_keys("NewPass123!")
driver.find_element(By.ID, "save-btn").click()
time.sleep(5) # 等待设备重启
# 验证设备是否在线
driver.get("http://192.168.1.1")
assert "登录" in driver.title
driver.quit()
4.6 横向对比:一张表说清楚
| 维度 | unittest | pytest | Robot Framework | Selenium |
|---|---|---|---|---|
| 学习曲线 | 低(标准库) | 中 | 低(关键字驱动) | 中 |
| 代码量 | 多(样板代码) | 少 | 少(但关键字库需提前封装) | 中等 |
| 硬件资源管理 | 手动setUp/tearDown | fixture(强大) | 通过Library管理 | 不适用 |
| 报告生成 | 需第三方库 | pytest-html(优秀) | 自带HTML报告 | 需配合pytest |
| 并行执行 | 不支持 | pytest-xdist | 支持(但配置复杂) | 需配合pytest |
| 适用场景 | 底层库单元测试 | 通用硬件测试(首选) | 非技术人员编写用例 | 嵌入式Web界面测试 |
4.7 我的最终选型建议
说了这么多,到底怎么选?我个人的经验是:
- 如果你是一个人单干,或者团队全是开发背景: 无脑选
pytest。它是最平衡的选择,既能写单元测试,也能做集成测试,插件生态能解决你90%的需求。 - 如果产线技术员也要写测试用例: 用
Robot Framework做上层封装,底层用Python库实现关键字。记住,关键字库一定要由资深工程师维护,否则会变成一锅粥。 - 如果被测设备有Web管理页面: 把
Selenium集成到pytest框架里,用pytest管理测试流程,用Selenium操作浏览器。这是最优雅的方案。 - 至于unittest: 除非你公司强制要求,或者项目有历史遗留代码,否则我建议你直接跳过。不是说它不好,而是pytest能做得更好。