多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

MicroPython 测试编写指南:从 tests 目录到 run-tests.py 测试运行器全解析

MicroPython 测试编写指南:从 tests 目录到 run-tests.py 测试运行器全解析 MicroPython 测试编写指南从 tests 目录到 run-tests.py 测试运行器全解析【免费下载链接】micropythonMicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems项目地址: https://gitcode.com/gh_mirrors/mi/micropythonMicroPython 拥有一个独立于各移植port的跨平台测试体系集中存放于仓库的tests/目录并以run-tests.py作为统一测试运行器。本篇指南以官方开发文档 docs/develop/writingtests.rst 为骨架结合 tests/run-tests.py 与 tests/test_utils.py 的源码实现系统讲解测试的组织结构、编写规范、run-tests.py全部命令行参数与典型使用场景。读完本文你将能够为 MicroPython 新增高质量测试并在 Unix 移植、开发板串口、webassembly 等多种目标实例上运行、筛选、并行化执行测试以及利用失败结果文件快速定位回归问题。测试体系总览目录结构与运行方式MicroPython 的测试全部位于仓库根的tests/目录。该目录下按功能域划分了多个子目录每个子目录中存放若干.py测试脚本及对应的.exp期望输出文件*.exp存在与否决定了测试结果的判定方式详见后文。典型的顶层结构如下. ├── basics # 语言基础特性测试 ├── extmod # extmod 模块测试 ├── float # 浮点运算测试 ├── micropython # MicroPython 特有功能测试 ├── run-tests.py # 测试运行器Python 脚本 ...除上述目录外仓库中还存在大量其他分类从 run-tests.py 的默认测试目录集合可以看到basics、micropython、misc、extmod、stress是通用默认目录若目标支持内联汇编、线程、浮点、Unicode会追加inlineasm/arch、thread、float、unicode同时会加载平台相关的ports/port目录如ports/unix、ports/stm32PC 平台unix/windows还会额外运行import、cmdline、io测试。新增测试的方式非常简单在某个现有子目录或新建子目录中创建一个.py文件即可。对于自定义移植custom port官方建议将专属测试放在tests/之外独立维护这样既不会污染上游测试集也便于随移植单独分发。第一个测试print 驱动的结果对比模型MicroPython 测试的核心判定模型是将测试脚本在 MicroPython 上的输出与同一脚本在 CPython 上的输出进行逐字节对比。因此编写测试的第一原则是——用print语句显式输出测试结果。没有输出或输出不稳定的测试无法参与对比。在tests/ports/unix/子目录下新建print.py内容如下def print_one(): print(1) print_one()随后进入 unix 移植目录执行make tests该目标会先构建 MicroPython 可执行文件再调用 run-tests.py见 ports/unix/Makefile新的测试便会出现在输出中$ cd ports/unix $ make tests skip unix/extra_coverage.py pass unix/ffi_callback.py pass unix/ffi_float.py pass unix/ffi_float2.py pass unix/print.py pass unix/time.py pass unix/time2.py每一行以pass/fail/skip等状态开头随后是测试相对tests/的路径。除了make testsunix 移植的 Makefile 还提供了若干便捷目标见 ports/unix/Makefilemake test-failures等价于./run-tests.py --run-failures只重跑上次失败的测试make test/name等价于-d name只运行指定目录make test_full_no_native/make test_full以--via-mpy、--emit native等组合执行更完整的回归。编写测试的规范与技巧用 print 表达断言因为测试通过比对输出来判定所以断言本质上就是“把结果打出来”。任何期望验证的值、异常行为、边界情况都应转化为确定的打印内容。若测试涉及名称或字符串相关功能官方建议同时覆盖英文/ASCII 与非英文/非 ASCII 文本并附带 Unicode 示例同时务必用英文注释说明 Unicode 文本的含义与意图从而确保 Unicode 支持在跨平台环境中被充分验证。.py.exp 文件脱离 CPython 的期望输出并非所有测试都能与 CPython 对比——MicroPython 特有功能如micropython模块、内存分配失败路径、extra_coverage等在 CPython 中根本不存在。此时可为测试提供同名的.py.exp文件作为对比基准truth。run-tests.py 的判定优先级在源码中有明确说明见 tests/run-tests.py优先使用test.exp文件作为期望输出否则才回退到用 CPython 运行测试生成期望输出使用 native emitter 时则优先查找test.native.exp。特殊头部指令与 feature_check部分测试文件支持#开头的特殊指令。例如cmdline/目录下的测试可通过# cmdline: args头指定传给 unix 可执行文件的命令行参数见 tests/run-tests.py# sigint:头用于指示需要发送 Ctrl-C 信号。另外tests/feature_check 目录存放的是“能力探测脚本”如target_info.py、float.py、inlineasm.pyrun-tests.py会先在目标实例上执行这些探测脚本自动获取平台、架构、浮点精度、线程与 Unicode 支持等信息见 tests/run-tests.py据此决定默认运行哪些测试目录。这也是为什么同一套测试在 PC 与开发板上会有不同取舍。run-tests.py 命令行参数详解目标实例与设备选择-t不传-t时默认使用 unix 移植。-t/--test-instance支持的取值类型在 tests/test_utils.py 中有权威定义取值含义unix使用 unix 移植由环境变量MICROPY_MICROPYTHON指定可执行文件默认是 unix 或 windows 移植的标准变体视宿主平台而定webassembly使用 webassembly 移植由MICROPY_MICROPYTHON_MJS指定默认ports/webassembly/build-standard/micropython.mjsport:device连接并使用给定的串口设备an连接/dev/ttyACMnun连接/dev/ttyUSBncn连接COMnWindowsexec:command执行命令并挂接到其 stdin/stdoutexecpty:command执行命令并挂接到其打印出的/dev/pts/n设备a.b.c.d连接给定的 IPv4 地址其他任意值视为串口设备路径设备快捷方式到真实路径的转换逻辑见 tests/test_utils.py。连接串口实例时还可配合-b/--baudrate默认 115200、-u/--user默认micro、-p/--password默认python设置波特率与 telnet 登录凭据。硬件目标通过 raw REPL 执行测试单测超时默认 30 秒MICROPY_TEST_TIMEOUT连续 3 次 raw REPL 失败即中止整轮测试见 tests/test_utils.py。测试选择-d / -i / -e / 文件参数-d, --test-dirs指定一个或多个测试目录如-d basics-i, --include REGEX仅运行路径/文件名匹配该正则的测试-e, --exclude REGEX排除路径/文件名匹配该正则的测试位置参数files直接列出具体测试文件如float/builtin*.py。-i/-e可多次出现按命令行顺序依次生效采用正则 search而非 match语义最后一个匹配到的规则决定取舍见 tests/run-tests.py./run-tests.py -i async # 先全部排除再包含含 async 的测试 ./run-tests.py -e /big.int # 先全部包含再按正则排除 ./run-tests.py -e async -i async_foo # 排除 async但仍包含 async_foo执行选项--emit / --via-mpy / --heapsize / -j--emit EMITTER指定 MicroPython 发射器取值为bytecode默认或native--via-mpy先将.py编译为.mpy再执行模拟跨编译分发场景。实现上通过mpy-cross将脚本编译进内存再利用注入的导入钩子加载见 tests/test_utils.py 与 tests/test_utils.py。可通过环境变量MICROPY_MPYCROSS指定特定版本的mpy-cross并用--mpy-cross-flags透传额外参数例如按检测到的架构自动追加-march...见 tests/run-tests.py--heapsize为测试设置堆大小如-X heapsize64k之类webassembly 实例上会透传该参数-j, --jobs N并行运行的测试数默认取 CPU 核数其他实用选项--dry-run仅列出将运行的测试--keep-path不清空MICROPYPATH默认会清空搜索路径确保只使用内置模块、extmod 与 unittest 标准库见 tests/run-tests.py-c/--trace-output实时打印测试输出--begin PROLOGUE在执行测试前先运行一段前导脚本。结果管理-r / --print-failures / --clean-failures / --run-failures-r, --result-dir结果目录默认tests/results/--print-failures打印失败测试的期望.exp与实际.out差异并退出。注意run-tests.py在运行前就会处理该选项见 tests/run-tests.py对已有结果文件做差异展示--clean-failures删除上次失败遗留的.exp、.out文件及结果记录--run-failures仅重跑上次失败的测试从results/_results.json中读取失败列表见 tests/run-tests.py且不能与files/-d同时使用。测试失败时运行器会在结果目录生成一对test.outMicroPython 实际输出与test.exp期望输出整轮结束后还会把参数与全部结果pass/fail/skip/ignored序列化到results/_results.json见 tests/test_utils.py。常用组合示例# 仅用 native 发射器运行 basics 与 extmod ./run-tests.py --emit native -d basics extmod # 排除 async 相关测试 ./run-tests.py -e async # 只运行匹配 *_pep_* 的测试 ./run-tests.py -i *_pep_* # 并行运行一组特定文件 ./run-tests.py -j 4 basics/list*.py # 在连接的 ESP32 开发板上运行 ./run-tests.py -t /dev/ttyUSB0 # 等价写法 ./run-tests.py -t u0 # 只重跑上次失败的测试 ./run-tests.py --run-failures测试运行的其他入口与环境变量从 tests 目录直接运行在tests/目录下直接执行./run-tests.py不传任何参数即可按默认规则自动探测目标并运行内置测试集$ cd tests $ ./run-tests.py # 默认 unix 移植 $ ./run-tests.py -t /dev/ttyACM0 # 运行在开发板上 $ ./run-tests.py -d basics # 只运行一个目录 $ ./run-tests.py float/builtin*.py # 运行指定文件关键环境变量环境变量作用默认值MICROPY_MICROPYTHONunix/windows 移植的可执行文件路径ports/unix/build-standard/micropython或 windows 版MICROPY_MICROPYTHON_MJSwebassembly 移植的.mjs路径ports/webassembly/build-standard/micropython.mjsMICROPY_CPYTHON3用于生成期望输出的 CPython 解释器python3Windows 下为pythonMICROPY_MPYCROSS--via-mpy使用的mpy-cross路径mpy-cross/build/mpy-crossMICROPY_DIFF失败差异展示所用的 diff 命令diff -uMICROPY_TEST_TIMEOUT单个测试的超时秒数30上述默认值均可在 tests/test_utils.py 与 tests/run-tests.py 中找到实现依据。需要说明的是CPython 端以-BS参数启动不生成.pyc、只访问核心标准库并强制PYTHONIOENCODINGutf-8以保证跨平台输出一致性。质量保障机制跳过、已知脆弱测试与报告为兼顾不同目标的能力差异run-tests.py内置了多级“跳过/豁免”机制见 tests/run-tests.py--via-mpy专用跳过表某些打印文件名、依赖源码路径的测试在.mpy模式下不适用emitter 专用跳过表native 发射器暂不支持raise varargs、raise from、sys.settrace等特性的测试会被跳过平台专用跳过表按esp8266、minimal、nrf、rp2、webassembly、zephyr等平台列出已知不适用或超时的测试例如 esp8266 上stress/list_sort.py会触发看门狗错误报告级别跳过表MICROPY_ERROR_REPORTING为terse/none时跳过依赖详细异常输出的测试已知脆弱测试flaky即使失败也会被重新归类为ignored而不影响 CI 退出码例如thread/thread_gc1.pyGC 竞态、cmdline/repl_lock.pyREPL 时序等规则以(原因, 平台)元组维护target_wiring 注入少数依赖硬件时序的测试如extmod/machine_uart_tx.py、extmod_hardware/machine_pwm.py需要import target_wiring运行器会自动按板级/移植级匹配tests/target_wiring/中的脚本注入见 tests/run-tests.py。这些机制共同保证了“同一份测试集跨 PC、MCU 与 wasm 三种形态都能给出稳定且可信的结果”。运行结束后摘要会依次输出执行数、通过数、已知脆弱忽略数、跳过数含“因太大而跳过”、失败数并全部落盘到results/_results.json供 CI 消费见 tests/test_utils.py。结语写测试的正确姿势回顾整个体系MicroPython 的测试哲学可以概括为三点输出即断言一切靠 print 与期望文件对比、差异即回归CPython 与 MicroPython 的双引擎对照辅以.py.exp承载 MicroPython 特有语义、平台即参数通过-t、feature_check 探测与多级跳过表让一套测试适配从桌面到 MCU 的全部运行环境。掌握 docs/develop/writingtests.rst 中描述的目录组织、文件命名与run-tests.py参数再结合 tests/run-tests.py 与 tests/test_utils.py 的源码细节你就能为任何 MicroPython 移植写出既规范又便于长期维护的测试。【免费下载链接】micropythonMicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems项目地址: https://gitcode.com/gh_mirrors/mi/micropython创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表