别再死记硬背了!用Python脚本自动化测试EC20模块的AT指令(附完整代码)
用Python脚本自动化测试EC20模块的AT指令实战指南
每次调试EC20模块时,在串口工具里反复输入AT指令的场景是否让你感到疲惫?作为一名长期与物联网模组打交道的开发者,我深刻理解手动测试的低效与痛苦——敲错一个字符就得重来,测试不同网络状态需要反复插拔SIM卡,批量验证功能时更是耗时耗力。本文将分享如何用Python的serial库构建自动化测试方案,让你从此告别重复劳动。
1. 环境搭建与基础连接
在开始编写自动化脚本前,需要准备以下硬件和软件环境:
-
硬件准备 :
- EC20模块开发板(带USB接口)
- 支持4G网络的SIM卡
- USB转串口线(如CP2102)
- 可选:外接天线(增强信号稳定性)
-
Python库安装 :
pip install pyserial
pip install pytest # 用于后续自动化测试框架
连接EC20模块后,首先需要确认设备节点。在Linux系统下,通常为 /dev/ttyUSB0 或 /dev/ttyACM0 ;Windows下则为 COM3 等端口。可以通过以下代码快速检测可用串口:
import serial.tools.list_ports
ports = serial.tools.list_ports.comports()
for port in ports:
print(port.device)
建立基础连接时,需要注意三个关键参数:波特率(默认115200)、超时时间和流控设置。以下是推荐的基础连接配置:
import serial
ser = serial.Serial(
port='/dev/ttyUSB0',
baudrate=115200,
timeout=1, # 秒
rtscts=False, # 禁用硬件流控
dsrdtr=False # 禁用DTR流控
)
提示:如果遇到连接问题,尝试在EC20模块上执行
AT+IPR?确认当前波特率,或使用AT+IFC=0,0关闭流控。
2. AT指令交互封装实战
直接使用串口发送原始指令不仅容易出错,也难以维护。我们需要构建一个健壮的指令交互层,包含以下核心功能:
- 自动添加
\r\n结束符 - 统一处理模块响应
- 支持超时重试机制
- 错误代码解析
2.1 基础指令发送函数
def send_at_command(ser, command, expected_response="OK", timeout=3, retries=3):
original_timeout = ser.timeout
ser.timeout = timeout
for attempt in range(retries):
ser.write(f"{command}\r\n".encode())
response = b''
while True:
line = ser.readline()
if not line:
break
response += line
decoded = response.decode().strip()
if expected_response in decoded:
return decoded
raise Exception(f"Command {command} failed after {retries} retries")
2.2 常用指令封装示例
将高频使用的AT指令封装成语义化的函数,大幅提升代码可读性:
def get_signal_quality(ser):
response = send_at_command(ser, "AT+CSQ")
# 典型响应:+CSQ: 24,99
parts = response.split(":")[1].strip().split(",")
return {"rssi": int(parts[0]), "ber": int(parts[1])}
def check_network_registration(ser):
response = send_at_command(ser, "AT+CREG?")
# 响应示例:+CREG: 2,1,"3747","A23C2",100
status = int(response.split(",")[1])
return {
0: "未注册",
1: "已注册",
2: "正在注册",
3: "注册被拒绝"
}.get(status, "未知状态")
2.3 错误处理增强
EC20模块支持通过 AT+CMEE=2 开启详细错误模式,这对调试至关重要:
def enable_verbose_errors(ser):
send_at_command(ser, "AT+CMEE=2")
def get_sim_info(ser):
try:
iccid = send_at_command(ser, "AT+QCCID")
imei = send_at_command(ser, "AT+GSN")
return {"iccid": iccid.split(":")[1].strip(),
"imei": imei.strip()}
except Exception as e:
print(f"获取SIM卡信息失败: {str(e)}")
return None
3. 构建自动化测试框架
当需要批量验证模块功能时,一个结构化的测试框架能显著提升效率。我们基于pytest构建可扩展的测试套件。
3.1 测试用例设计
创建 test_ec20.py 文件,包含核心功能测试:
import pytest
@pytest.fixture(scope="module")
def ec20_connection():
ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=1)
yield ser
ser.close()
def test_signal_quality(ec20_connection):
quality = get_signal_quality(ec20_connection)
assert 0 <= quality['rssi'] <= 31, "信号强度值异常"
def test_network_registration(ec20_connection):
status = check_network_registration(ec20_connection)
assert status == "已注册", f"网络注册失败: {status}"
def test_sim_card(ec20_connection):
info = get_sim_info(ec20_connection)
assert info['iccid'] and len(info['iccid']) == 20, "ICCID无效"
assert info['imei'] and len(info['imei']) == 15, "IMEI无效"
3.2 参数化测试
使用pytest的参数化功能批量测试不同配置:
@pytest.mark.parametrize("baudrate", [9600, 19200, 38400, 57600, 115200])
def test_baudrate_change(ec20_connection, baudrate):
send_at_command(ec20_connection, f"AT+IPR={baudrate}")
send_at_command(ec20_connection, "AT&W") # 保存设置
# 需要重新初始化连接
new_ser = serial.Serial('/dev/ttyUSB0', baudrate, timeout=1)
assert new_ser.baudrate == baudrate
new_ser.close()
3.3 测试报告生成
添加以下命令生成美观的HTML报告:
pytest --html=report.html --self-contained-html
4. 高级应用与性能优化
当基础功能稳定后,可以进一步优化测试效率和扩展性。
4.1 并发测试策略
使用多线程同时测试多个功能模块:
from threading import Thread
def concurrent_test():
results = {}
def test_func(target, name):
results[name] = target()
threads = [
Thread(target=test_func, args=(lambda: get_signal_quality(ser), "signal")),
Thread(target=test_func, args=(lambda: check_network_registration(ser), "network")),
Thread(target=test_func, args=(lambda: get_sim_info(ser), "sim"))
]
for t in threads:
t.start()
for t in threads:
t.join()
return results
4.2 响应时间分析
通过装饰器记录关键操作的执行时间:
import time
from functools import wraps
def timing(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} executed in {end-start:.3f}s")
return result
return wrapper
@timing
def extended_test_sequence(ser):
send_at_command(ser, "AT+CSQ")
send_at_command(ser, "AT+CREG?")
send_at_command(ser, "AT+GSN")
4.3 自动化测试CI集成
将测试脚本集成到Jenkins或GitHub Actions中,实现持续验证:
# .github/workflows/test.yml 示例
name: EC20 Module Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pyserial pytest pytest-html
- name: Run tests
run: |
python -m pytest test_ec20.py --html=report.html --self-contained-html
- name: Upload report
uses: actions/upload-artifact@v2
with:
name: test-report
path: report.html
在实际项目中,这套自动化测试方案将测试时间从原来手动操作的30分钟缩短到2分钟以内,且避免了人为错误。一个特别有用的技巧是在测试前自动执行 AT+CMEE=2 开启详细错误模式,这让我们快速定位到一处波特率配置不匹配的问题,节省了大量调试时间。
更多推荐

所有评论(0)