
本文介绍在 qftest 自动化测试中,可靠验证 java hmi 应用是否真正终止的实践方法,强调避免 shutdown 期间与 sut 的通信干扰,并推荐使用内置终止节点、强制进程杀除及健壮性轮询策略。
本文介绍在 qftest 自动化测试中,可靠验证 java hmi 应用是否真正终止的实践方法,强调避免 shutdown 期间与 sut 的通信干扰,并推荐使用内置终止节点、强制进程杀除及健壮性轮询策略。
在 QFTest 中验证 Java 应用(尤其是图形化人机界面 HMI)是否已彻底关闭,是端到端测试收尾阶段的关键质量门禁。许多用户尝试在 shutdown 后通过主动发送 socket 或调用 rc.toSUT() 来探测应用存活性,但该方式存在根本性风险:QFTest 的 Java Agent 在应用生命周期管理中会维持部分连接通道,导致即使 UI 线程已退出,SUT 客户端仍可能处于“假存活”状态——表现为 socket 可连通或 toSUT 不抛异常,从而误判 shutdown 失败。
✅ 推荐方案:分层验证 + 主动终止控制
-
优先使用 QFTest 原生终止机制
避免在 shutdown 过程中任何主动通信。正确做法是:- 录制用户真实退出操作(如点击「退出」菜单、关闭主窗口);
- 在测试流程末尾,显式插入 Terminate SUT 节点(位于 Procedures → Terminate SUT),该节点会触发 QFTest 对 JVM 的标准 shutdown hook 调用,并等待进程真正退出;
- 若需强制终止,可选用 Kill SUT 节点(对应 kill -9 行为),适用于僵死进程场景。
进程级存在性验证(推荐替代 socket 探测)
当必须编程验证时,应绕过 QFTest 通信层,直接检查操作系统进程状态:
import subprocess
import time
def is_sut_process_dead(pid_or_name, timeout=30, interval=0.5):
"""
检查指定 PID 或进程名是否已从系统中消失
注意:需提前通过 rc.getLocal("sutPid") 或启动脚本记录 PID
"""
start_time = time.time()
while time.time() - start_time < timeout:
try:
# Windows 示例(使用 tasklist)
if subprocess.run(["tasklist", "/FI", f"PID eq {pid_or_name}"],
capture_output=True, text=True).stdout.strip().count("INFO") == 0:
return True
except:
pass # 进程不存在即报错,视为已终止
# Linux/macOS 替代命令:subprocess.run(["kill", "-0", str(pid_or_name)], ...)
time.sleep(interval)
return False
# 在 QFTest Jython 过程中调用
if is_sut_process_dead(vars.get("sutPid", "unknown")):
rc.setLocal("shutdownVerified", True)
else:
rc.setLocal("shutdownVerified", False)-
关键注意事项
- ❌ 禁止在 shutdown 执行中调用 rc.toSUT():Java Agent 会阻塞或延迟 JVM 终止,造成检测逻辑失效;
- ✅ 启动时务必记录 SUT 进程 PID:在 Start SUT 节点后,通过 rc.setLocal("sutPid", ...) 保存 PID(QFTest 7.0+ 支持 rc.getProcessId());
- ? 轮询需设合理超时与间隔:示例中 30 秒总超时 + 500ms 间隔兼顾响应性与稳定性;
- ? 参考官方范例:QFTest 安装目录下的 demo/carconfig/carconfig_en.qft 中 startStop.terminate 过程,完整演示了安全启停与状态校验模式。
综上,可靠的 shutdown 验证不依赖于应用层通信反馈,而应立足于操作系统进程生命周期管理。结合原生 Terminate SUT 节点、PID 跟踪与跨平台进程探测,可构建稳定、可复现的终止验证流程,显著提升自动化测试结果的可信度。










