.NET Core 6中ShowDialog单元测试卡顿问题求助
解决.NET Core单元测试中ShowDialog阻塞问题的两种方案
方案一:通过Mock隔离UI依赖(推荐用于单元测试)
核心思路是把对话框的显示和结果获取逻辑抽象成接口,让业务代码依赖接口而非具体的对话框类,这样单元测试时可以用Mock框架模拟返回结果,完全避免弹出真实窗口。
步骤1:抽象接口
定义封装对话框核心行为的抽象接口:
public interface IDatabaseTableSelector { bool ShowDialog(); object SelectedTable { get; } // 根据实际类型调整,比如你的selectedTable是字符串就用string }
步骤2:适配原有对话框类
如果能修改原DatabaseTableSelection类,直接让它实现接口:
public class DatabaseTableSelection : Form, IDatabaseTableSelector { public object selectedTable { get; private set; } // 原有构造函数和业务逻辑保持不变 public new bool ShowDialog() { base.ShowDialog(); return selectedTable != null; } object IDatabaseTableSelector.SelectedTable => selectedTable; }
如果无法修改原类,就写个适配器类做中转:
public class DatabaseTableSelectorAdapter : IDatabaseTableSelector { private readonly DatabaseTableSelection _dialog; public DatabaseTableSelectorAdapter(string filePath, object contr) { _dialog = new DatabaseTableSelection(filePath, contr); } public bool ShowDialog() { _dialog.ShowDialog(); return _dialog.selectedTable != null; } public object SelectedTable => _dialog.selectedTable; }
步骤3:修改业务代码依赖接口
把直接实例化对话框的逻辑,改成依赖接口传入:
public bool YourBusinessLogic(IDatabaseTableSelector tableSelector) { tableSelector.ShowDialog(); if (tableSelector.SelectedTable == null) { return false; } // 后续业务逻辑 return true; }
步骤4:单元测试中Mock接口(以Moq为例)
安装Moq NuGet包后,在测试中模拟接口返回值:
[Test] public void WhenTableIsSelected_ReturnsTrue() { // 创建Mock对象 var mockSelector = new Mock<IDatabaseTableSelector>(); // 模拟ShowDialog返回true,预设选中表的值 mockSelector.Setup(s => s.ShowDialog()).Returns(true); mockSelector.Setup(s => s.SelectedTable).Returns("Test_Table"); // 调用业务方法 var result = YourBusinessLogic(mockSelector.Object); // 断言结果符合预期 Assert.IsTrue(result); } [Test] public void WhenNoTableSelected_ReturnsFalse() { var mockSelector = new Mock<IDatabaseTableSelector>(); mockSelector.Setup(s => s.ShowDialog()).Returns(false); mockSelector.Setup(s => s.SelectedTable).Returns(null); var result = YourBusinessLogic(mockSelector.Object); Assert.IsFalse(result); }
方案二:用FlaUI自动化操作真实对话框(适合集成测试)
如果需要验证真实UI的交互逻辑,可以用你已在使用的FlaUI,在测试中自动操作对话框:
[Test] public void TestDatabaseTableSelectionFlow() { bool dialogResult = false; object selectedTable = null; // 在STA线程启动对话框(WinForms必须用STA线程) var dialogThread = new Thread(() => { var tableSelection = new DatabaseTableSelection("test_file_path", null); tableSelection.Topmost = true; dialogResult = tableSelection.ShowDialog() == DialogResult.OK; selectedTable = tableSelection.selectedTable; }); dialogThread.SetApartmentState(ApartmentState.STA); dialogThread.Start(); // 等待窗口加载(也可以用FlaUI的WaitFor方法替代硬编码等待) Thread.Sleep(500); // 用FlaUI定位窗口并操作 var currentApp = FlaUI.Core.Application.Attach(Process.GetCurrentProcess()); var dialogWindow = currentApp.GetMainWindow(cf => cf.ByTitleContains("DatabaseTableSelection")); // 切换到目标Tab页 var tabControl = dialogWindow.FindFirstDescendant(cf => cf.ByControlType(FlaUI.Core.Definitions.ControlType.Tab)).AsTab(); tabControl.SelectTabItem(1); // 选择网格项(根据实际UI结构调整) var dataGrid = dialogWindow.FindFirstDescendant(cf => cf.ByControlType(FlaUI.Core.Definitions.ControlType.DataGrid)).AsDataGrid(); dataGrid.Rows[0].Select(); // 点击OK按钮 var okBtn = dialogWindow.FindFirstDescendant(cf => cf.ByText("OK")).AsButton(); okBtn.Click(); // 等待对话框线程结束 dialogThread.Join(); // 断言结果 Assert.IsTrue(dialogResult); Assert.IsNotNull(selectedTable); }
注意:这种方式属于集成测试,依赖真实UI环境,执行速度比Mock方案慢,需要确保测试环境的UI元素与代码匹配。
内容的提问来源于stack exchange,提问作者Joseph Gabello
相关产品推荐
相关产品推荐

