CODESYS AI实践 - 单元测试
环境:CODESYS V3.5 SP17 | SoftMotion Win 64 | Windows + PowerShell 5.1
上一篇《CODESYS AI实践 - 在线连接》把程序下载进软 PLC,能启停、能读写变量。
这一篇让 AI 给 Codesys 写单元测试。
目标是一句话让 AI 补测试:它自己能写单元测试、导入工程、给红绿报告等;也支持回归等标准单元测试场景。
选型
CODESYS 单元测试不是新课题。GitHub等 的现有方案大致分几类:
| 方案 | 测什么 | 仿真 / 真机 | 代价 |
|---|---|---|---|
| 主机 pytest 驱动 read/write | 黑盒接口 | 均可 | 断言离现场远,时序不确定,周期内的细节难覆盖 |
| Matiec 离线编译检查 | 纯逻辑 | 不连运行时 | 覆盖不到轴控、在线状态和通讯 |
| CoUnit / UniTest(库进 PLC) | 白盒 | 均可 | 要装库;社区库多数停更,生成代码要适配具体 API |
| CODESYS Test Manager(3S) | 白盒 | 均可 | 商业付费,OEM 环境功能常受限 |
| 自写 ST 断言 + 主机收集 | 白盒 | 均可 | 要自己维护协议,但 PLC 侧零依赖,结构可控 |
主要分歧在断言放在哪、结果怎么回。
选择了一下,决定:
- 断言和逻辑放在一起:断言和被测逻辑在同周期执行,看同一份变量;
- 无依赖:PLC 侧不装库、不引授权;
- 有测试报告:主机能拿到统一结果,接报告和 CI。
- 设计风格:按照xunit的风格设计
采用了一种轻量方式:把 xunit 的 suite / test / assert / fixture 概念映射到 ST,测试跟应用一起编译,不引入 xunit 框架,也不在 PLC 里装第三方库。
原理

测试代码也是标准的ST语言,跟应用一起编译、一起下载;断言和被测逻辑在同一个周期、同一份变量上执行。主机不参与断言,只负责把这一轮跑起来并读回结果。
一轮的流程:
- 套件由
PRG_Tests在循环任务里调用。 - 每个用例按
Setup→ 断言 →TearDown执行。 - 断言把结果写进
GVL_Test的用例表。 - 所有套件完成后置完成标志,告诉主机这一轮结束。
- 主机轮询完成标志,读回计数和用例,校验后生成报告。
xunit映射
xunit映射关系:
- suite 对应
FB_<Unit>_Test功能块 - test 对应 suite 上的
Test_*方法 - assert 对应
ass.AssertEquals_*/AssertTrue等调用 - fixture 对应
Setup/TearDown和 suite 的VAR
能力与场景
这套结构能覆盖的范围:
| 能力 | 说明 |
|---|---|
| 测试组织 | suite / test / assert / fixture,固定词汇 |
| 断言 | 数值、布尔、整型;支持 Skip |
| 运行目标 | SoftMotion / Control Win 仿真与真机 |
| 结果 | 文本报告、JUnit XML、退出码 |
| 连续执行 | 复位 + 读回,支持多轮 |
| 定位 | g_sFilter 单套件、g_sFirstFailure 首条失败 |
| 保护 | 0 用例、套件数、失败数、64 条容量 |
| 依赖 | PLC 侧零依赖;主机复用 codesys-connect / codesys-sync |
对应的场景:
- 功能开发:先写
FB_<Unit>_Test,测试驱动。 - 回归门禁:接 CI回归。
- 仿真与真机:支持仿真与真机。本地仿真由主机自动拉起,真机用
-Address/-Port指定。 - 接口验证:需要黑盒校验时,配合 codesys-connect 的读写补集成用例。
- AI 批量生成:结构固定,生成结果稳定,便于复审和比较。
项目样子
采用后,项目里会多出一个 Tests 目录,产线逻辑仍在 Application 根下:
<repo>/
projects/<App>.project
src/plc/<App>/
Application/
F_DecideSort.st # 产线逻辑
FB_Diverter.st
FB_Conveyor.st
FB_Stats.st
Tests/ # 测试对象
UT_Case.st
GVL_Test.st
FB_Assert.st + methods
FB_Diverter_Test.st + methods
PRG_Tests.st
Task Configuration/
MainTask # 测试工程:挂 PRG_Tests
structure_ops.txt
projects/out/ # report.txt / junit.xml / results.json
边界:PRG_Tests 挂在一个循环任务上,产线任务不调用它;发布时可以把 Tests 整体排除,不会把断言带进生产。
套件只做编排,把 Setup / Test_* / TearDown 串起来:
FUNCTION_BLOCK FB_Diverter_Test
VAR
ass : FB_Assert;
fb : FB_Diverter;
END_VAR
IF NOT ass.Begin('Diverter') THEN
RETURN;
END_IF
Setup();
Test_DoesNotPushWhenIdle();
TearDown();
Setup();
Test_ExtendsAfterDelayThenRetracts();
TearDown();
ass.Finish();
用例里只写断言,比如 ass.AssertEquals_DINT('Stats.Test_pass', 1, TO_DINT(fb.uiPass) - TO_DINT(uiPass0));。
工程侧的约定:
PRG_Tests挂在循环任务(测试工程或独立测试任务),产线任务不调用它。- 套件名
FB_<Unit>_Test,方法Test_<行为>,Setup/TearDown包住每个用例。 g_uiSuitesTotal和实际调用的套件一致;示例里按g_sFilter计算。- 报告落在
projects/out/,report.txt给人看,junit.xml给 CI。
使用方式
cc.ps1 connect -Project <abs .project> -UserFile <user.txt>
cc.ps1 download
ut.ps1 run -Project <abs .project> -UserFile <user.txt>
run 不下载;-Mock / -MockFail 可以在没有 PLC 时检查报告链路。退出码 0 表示通过,1 表示失败或流程错误。
验证说明
examples/sample-app/ 的 5 条用例在 SoftMotion Win 64 上跑过;conveyor 的 19 条用例与红绿、两轮、超时步骤写在 docs/CLOSED_LOOP.md。真机没有重跑,步骤见 docs/LIVE_SMOKE.md。
地址
仓库:https://github.com/zhouyongh/codesys-unittest
样例:examples/conveyor-loop/,测试风格:docs/TEST_STYLE.md,live 清单:docs/LIVE_SMOKE.md。
依赖上一环:codesys-connect(在线通道)、codesys-sync(导入工程)。
注意事项
- 版本匹配:工程、CODESYS、运行目标版本要匹配。
- 设备类型要对:SoftMotion Win V3 x64 是
4102/0000 0004,运行目标也必须是 SoftMotion,不能换成 Control Win。 - 下载与运行分开:
run只用change=Never登录;装载新逻辑显式download。Force会停应用、清变量。 PRG_Tests挂在循环任务(测试工程或独立测试任务),g_uiSuitesTotal和实际套件一致,否则g_xDone提前或永远不到。- 一个
Assert记一条 case;多断言方法会贡献多条记录。 - 两轮跑用增量断言;绝对计数第二轮就会红。
- 环境变量配置:用
-UserFile或环境变量,不把密码写进仓库。

浙公网安备 33010602011771号