Aspen HYSYS 二次开发系列教程(19):校验与回归测试体系——可复现性三件套与判定线固化
版本声明块
- 软件:aspenONE V15(基线,同第 1 篇);文档现实:Customization Guide V7.3(2011-03)为公开手册基线
- 语言/环境:Python(pywin32);回归脚本形态(第 14/15 篇服务分界为运行环境)
- 本文目标:把散在各篇的判定线收拢为一个可执行的测试体系——每次改动后跑一遍即知是否退化
一句话结论:HYSYS 自动化项目的可复现性三件套是——实际运行版本快照、属性确证清单(dir() 存档)、判定线清单;在线场景扩展为五件(加时钟源与时区、数据新鲜度阈值);回归测试的验收标准不是"跑通"而是每条判定线可量化复跑:连续 N 次输出一致、FAIL 占比 <20%、与基线对照差 <10%(同一口径)。
〇、本篇要解决的认知问题
- 三件套各解决哪类不可复现事故——缺哪一件对应哪条铁律?
- "命名契约"为什么必须登记——名称漂移导致的失败如何归因(第 2/5/16 篇机制合流)?
- 回归测试的最小脚本形态是什么——与手动验证的分界在哪?
- 判定线清单里哪些条目是跨机器可执行的、哪些只能人工抽查?
- 在线场景五件套比三件套多的两项为什么不可省(第 18 篇机制在此固化)?
一、机制解析
1.1 三件套与事故对应表(价值锚点:测试体系的价值在于把"凭印象"变成"可执行")
| 件 | 内容 | 对应的不可复现事故 |
|---|---|---|
| ① 版本快照 | 实际运行版本(铁律 1——ProgID 解析到当前安装版本) | 跨机器结果漂移;文档基线≠运行版本 |
| ② 属性确证清单 | dir() 存档 + "未证实"标注(铁律 7) | 旧手册属性名在新版本报错(V7.3 时代名称) |
| ③ 判定线清单 | 每条可量化验收线(守恒 <1e-6、抖动 >1%、对照差 <10% 等) | "跑通"与"工程成立"的混淆——假阳性进报表(铁律 6) |
在线五件新增:④ 时钟源与时区(clock_ref)、⑤ 数据新鲜度阈值(staleness limit)——缺④无法判断估计对应哪个时刻,缺⑤旧时刻估计会被当当前值引用(第 18 篇机制固化)。
1.2 命名契约登记(合流点:第 2/5/16 篇的"把名称当契约管理")
回归体系里名称不是字符串而是契约:stream "Feed"、operation "Unit1"、列名与方向(第 16 篇)、组分清单(第 5 篇)。登记最小三列:对象名、所属 case、写入源(第 10/16 篇单一写入源纪律)。判定线:任一 FAIL 行能还原"哪个 case、哪一次 Run、哪个写入源"——名称漂移导致的失败归因为契约破坏而非代码 bug。
1.3 回归测试最小脚本形态与分界
手动验证: 跑一次、看结果合不合理 ← 不叫测试 回归测试: 固定输入 → 连续 N 次运行 → 每条判定线自动核对 → 退出码可被调度捕获(第 14/15 篇)分界三条:① 失败可被上层捕获(非 0 退出码);② 无 GUI 依赖(第 15 篇);③ 连续运行输出一致(可审计性)。经验法则:判定线里"只能人工抽查"的条目(如物理方向合理性、报表口径争议)单独列出——脚本覆盖不了的部分必须写进文档,不能默认省略。
1.4 跨机器复跑验收(三件套齐才算可复现)
第三方按文档在另一台机器复跑的判定标准:输出一致(相对误差 <1e-6);属性确证清单与运行版本快照对齐;判定线逐条打勾——缺列即判定不通过(第 14 篇八列在此复用为测试数据格式)。
二、完整代码与逐行剖析
2.1 最小回归测试脚本(复制即跑;参数为示例值)
importwin32com.client,datetime,csv,sys BASELINE={"Feed_T":25.0}# 基线工况——固定输入才能定义"退化"(1.3)LINES={"conservation_tol":1e-6,"jitter_tol":0.01,"reps":10}# 判定线清单(③件套的脚本化)defone_run(sim,stream_name):row={"status":"OK","ts":datetime.datetime.now(datetime.timezone.utc).astimezone().isoformat(),"version":"<actual running version — record from machine>",# 件①(铁律 1)"run_ref":None,"clock_ref":"<record clock source & tz>",# 件④(在线场景——第 18 篇固化)"staleness_limit_s":60}# 件⑤props=dir(sim)forcandin("ErrorList","Messages"):# 未证实成员——存在才检查(铁律 7)ifcandinprops:err=getattr(sim,cand)cnt=getattr(err,"Count",None)ifcntandcnt>0:row.update(status="FAIL",run_ref=cand);returnrow stream=sim.Flowsheet.MaterialStreamFlowsheetStreams.Item(stream_name)# 名称契约(1.2)if"Temperature"notindir(stream):# 件②:确证后才访问(铁律 7)row.update(status="CODE_ERROR");returnrow stream.Temperature.Value=BASELINE["Feed_T"]try:sim.Run()# 成员名以本机为准(铁律 7)exceptExceptionase:row.update(status="CODE_ERROR",value=str(e));returnrow row["value"]=getattr(stream.Temperature,"Value",None)row["run_ref"]="clean run"returnrow app=win32com.client.Dispatch("HYSYS.Application")# 位数一致(铁律 3);实例与许可记录(第 15 篇)sim=app.ActiveDocument# 服务场景用 Documents 显式绑定(第 2 篇)rows=[one_run(sim,"Feed")for_inrange(LINES["reps"])]# ——判定线自动核对——ok_rows=[rforrinrowsifr["status"]=="OK"]values=[r["value"]forrinok_rows]fail_share=(len(rows)-len(ok_rows))/len(rows)jitter=max(values)-min(values)ifvalueselseNoneprint("conservation/jitter check:",jitter,"fail share:",fail_share)# 判定线:连续 N 次输出一致(本例以抖动 <1% 为量化形态);FAIL 占比 <20%(第 8/14 篇合流)iffail_share>=0.2or(jitterisnotNoneandjitter>LINES["jitter_tol"]*max(values)):sys.exit(2)# 回归失败——退出码可被调度捕获(1.3 分界①)逐行要点:三件套在代码里各有落点(version、dir() 确证、判定线自动核对);"只能人工抽查"的条目(物理方向合理性)不在脚本内假装覆盖——写进文档是判定线的一部分(1.3)。
三、常见报错与排查
- 跨机器结果漂移—— 现象:同一脚本两台机器输出不同。根因:版本快照缺失或属性确证清单未对齐(件①②)。解法:按 1.4 复跑验收——缺列即判定不通过(第 14 篇八列为测试数据格式)。
- 名称漂移归因为代码 bug—— 现象:Item(“Feed”) 失败被当属性问题修。根因:命名契约未登记、case 或写入源变更(1.2)。解法:契约三列登记;失败归因先查契约再查代码。
- 判定线"只能人工抽查"条目被省略—— 现象:测试全绿但报表口径争议爆发(第 7/13 篇机制)。解法:单独列出人工条目——脚本覆盖不了的部分必须写进文档(1.3)。
- 在线场景缺五件套两项—— 现象:估计值与现场时间不可比、旧时刻估计被引用(第 18 篇机制在此固化)。解法:clock_ref 与 staleness limit 进测试数据格式;超阈值行不得进入下游。
四、动手练习
- 三件套齐备复现:按 2.1 完成并制造一次回归失败(如连续抖动 >1%)。判定标准:退出码非 0 被调度捕获;三件套落点逐项可指认——缺项列清单补齐后复跑。
- 跨机器验收演练:把测试数据格式(八列)交给第三方在另一台机器复跑。判定标准:输出一致(相对误差 <1e-6)且判定线逐条打勾;差异处能归因到件①②④⑤中的具体一项。
- 思考题(无标准答案):为什么"跑通"不能当测试通过?验证要点清单:① 写出"跑通但假阳性进报表"的场景(铁律 6);② 给出回归分界三条各自对应的代码位置(1.3);③ 说明判定线清单里人工条目与自动条目的比例应如何管理(全绿≠可交付)。
五、小结与下一篇预告
本篇把全系列判定线收拢为可执行的测试体系:三件套(在线五件)、命名契约、退出码分界。第 20 篇完整实战项目——压缩机-分离线自动化闭环——把对象模型、断言、批量、优化与在线口径合流为一个可交付件,判定线逐层闭合即全系列收束。
本篇认知问题回显(FAQ)
Q1:HYSYS 自动化项目的可复现性三件套是什么?在线场景扩展为哪五件?
A:三件套——实际运行版本快照、属性确证清单(dir() 存档+未证实标注)、判定线清单;在线场景加时钟源与时区(clock_ref)与数据新鲜度阈值(staleness limit)共五件——缺前两项无法判断估计对应哪个时刻或属性是否可访问。
Q2:命名契约为什么必须登记?失败如何归因?
A:对象名、列名与方向是跨脚本的契约——最小三列为对象名、所属 case、写入源;Item(“Feed”) 失败若源于 case/写入源变更应归因为契约破坏而非代码 bug;任一 FAIL 行能还原"哪个 case、哪一次 Run、哪个写入源"即达标。
Q3:回归测试与手动验证的分界是什么?
A:三条——① 失败可被上层调度捕获(非 0 退出码);② 无 GUI 依赖;③ 连续 N 次运行输出一致(可审计性);判定线里"只能人工抽查"的条目(物理方向合理性、报表口径争议)必须单独写进文档,不能默认省略。
Q4:跨机器复跑的验收判定标准是什么?
A:第三方按文档复跑输出一致(相对误差 <1e-6)、属性确证清单与运行版本快照对齐、判定线逐条打勾——缺列即判定不通过;差异处能归因到三件套/五件套中的具体一项。
Q5:为什么"跑通"不能当测试通过?
A:跑通只证明脚本执行完成,不证明收敛(铁律 6)、口径一致(系列口径)或连续运行稳定(可审计性)——测试通过的定义是每条判定线可量化复跑:连续 N 次输出一致、FAIL 占比 <20%、与基线对照差 <10%(同一口径)。