You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 06:35:16