c# - “调用线程必须是STA,因为许多UI组件都需要这个”单元测试期间的异常
问题描述
我有一个名为 OptionsWindow 的类,它继承自 Window ,用于从窗口中的选项中进行选择。还有一个处理这些对话框的对话框类。在我的测试中,我试图模拟从对话框中选择的选项。
[TestMethod]
public async Task Test()
{
dialog.Setup(e => e.ShowDialog(It.IsAny<Window>(), It.IsAny<IntPtr>()))
.Returns(true)
.Callback<Window, IntPtr>((w, ip) => {
if (w.DataContext != null && w.DataContext is OptionsViewModel ovm)
ovm.Result = -1;
});
await tester.ShowWindow();
//assert....
}
然后在正在测试的课程中,我有这些方法。
public async Task ShowWindow()
{
var res = ShowDialog();
//do other stuff...
}
private int ShowDialog()
{
OptionsViewModel vm = //.....
dialog.ShowDialog(new OptionsWindow(vm));
return vm.Result;
}
但是,当它尝试设置 OptionsViewModel 的结果时,我收到错误“调用线程必须是 STA,因为许多 UI 组件需要这个”。
在手动测试期间,一切正常,没有线程问题,所以我不知道为什么我在这里得到这些......任何帮助都很棒。谢谢
(我使用 Microsoft.VisualStudio.TestTools.UnitTesting 顺便说一句)
解决方案
在我的测试中,我试图模拟从对话框中选择的选项。
通常,如果编写测试很困难,则表明代码应该设计得更好。
在这种情况下,直接依赖 UI 组件并不理想。有一种称为端口和适配器(又名六边形架构,又名清洁架构)的模式在这里会有所帮助。总之,您从应用程序的角度定义接口,然后让小型适配器对象实现这些接口。
所以你可以让应用程序定义一个接口来提供它需要的东西:
public interface IUserInteraction
{
int ModalOptionsWindow();
}
有一个实现:
public sealed class WpfUserInteraction : IUserInteraction
{
int ModalOptionsWindow()
{
OptionsViewModel vm = //.....
dialog.ShowDialog(new OptionsWindow(vm));
return vm.Result;
}
}
界面涵盖的具体内容取决于您。通常,我喜欢将我的 ViewModel 保留在端口的应用程序端,并且只在端口的 UI 端有视图。
一旦你有一个接口,注入IUserInteraction
并让你的代码调用它。之后,简化了单元测试。
但是,如果您处于遗留代码场景中,需要在重构之前编写测试,那么您可以对 UI 代码进行单元测试。这并不容易。请参阅WpfContext
或WindowsFormsContext
在此旧存档中查看创建 STA 线程并从单元测试中抽取消息的方法。
推荐阅读
- android - 为什么 Google 身份验证令牌刷新最近在适用于 Android 的 Azure 移动应用 SDK 中一直失败
- javascript - 在子跨度删除后删除子跨度删除剩余子自动重新排列为什么?
- laravel - 如何从引导方法调用 Facades 方法?
- regex - 如何在记事本++中删除数字之间的文本
- powershell - 使用 powershell 从注册表中选择路径
- django - SimpleListFilter 对管理表单没有影响,Django 2.2.8
- sql-server - SQL Server 2012 中的安全 .bak 文件
- validation - java.lang.Exception: HV000041: 调用 TraversableResolver.isReachable() 引发异常
- asp.net-core - 如何进行基于 Azure AD 组的授权?
- java - 如何使用 java lambda 表达式将 List 传递给新对象的构造函数?