X++单元测试中无法关闭系统生成的SysBoxForm问题求助
在Dynamics AX环境中,从CPool表单打开SysQueryForm后,点击【确定】关闭该表单时,会弹出一个系统生成的SysBoxForm对话框。编写单元测试尝试关闭该对话框时,使用以下X++代码:
using (SysBoxFormAdaptor sysBoxForm = SysBoxFormAdaptor::attach()) { sysBoxForm.CloseCtrl().click(); }
运行后触发如下错误:
Cannot access form CPool id 3: topmost form is SysBoxForm id 181
There are open forms on the client: {"CPool (3)", "SysBoxForm (181)"}
背景说明:CPool表单中点击按钮会打开SysQueryForm,因关联表的连接问题,选择筛选条件后会触发该系统对话框,目前暂无法修复此连接问题。核心需求是在单元测试中关闭这个内核级的SysBoxForm对话框。
1. 直接遍历顶层表单并关闭SysBoxForm
跳过表单适配层,直接遍历当前客户端的顶层表单,定位到SysBoxForm后调用关闭方法:
FormRun sysBoxForm; int formIndex; for (formIndex = 1; formIndex <= ClientFormRun::topLevelFormCount(); formIndex++) { sysBoxForm = ClientFormRun::topLevelForm(formIndex); if (sysBoxForm && sysBoxForm.name() == formstr(SysBoxForm)) { sysBoxForm.close(); break; } }
这种方法直接操作表单实例,避免适配层的层级访问限制问题。
2. 利用Windows API模拟键盘关闭对话框
SysBoxForm通常支持Esc键关闭,可通过WinAPI模拟按键操作:
HWND sysBoxHwnd; // 查找SysBoxForm的窗口句柄 sysBoxHwnd = WinAPI::findWindow(formstr(SysBoxForm), ''); if (sysBoxHwnd) { WinAPI::setForegroundWindow(sysBoxHwnd); // 模拟按下并释放Esc键 WinAPI::keybd_event(VK_ESCAPE, 0, 0, 0); WinAPI::keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0); }
注意:此方法依赖Windows系统API,需确保测试环境的权限支持,且表单窗口标题匹配(若有自定义标题需调整第二个参数)。
3. 临时禁用对话框触发逻辑
若无法修复底层连接问题,可在单元测试初始化时,临时跳过触发SysBoxForm的代码逻辑:
// 在测试类的setUp方法中添加全局标记 public void setUp() { super(); global::setTestMode(true); } // 在触发对话框的业务代码中添加判断 if (!global::isRunningUnitTest()) { // 原有的弹出SysBoxForm的逻辑 SysBoxForm::run(...); }
这种方法需要定位到触发对话框的具体业务代码,适合长期维护的测试用例,从根源避免对话框弹出。
4. 注册表单事件处理程序自动关闭
利用AX测试框架的表单事件处理机制,在SysBoxForm初始化时自动关闭:
[FormHandler(formstr(SysBoxForm), FormEventType::Initialized)] public static void SysBoxForm_OnInitialized(xFormRun _sender, FormEventArgs _e) { _sender.close(); }
在单元测试类中注册该处理程序,当SysBoxForm加载完成后会自动执行关闭操作,无需手动触发。
内容的提问来源于stack exchange,提问作者zester

