为什么关闭在单元测试中创建的窗口会引发InvalidComObjectException

本文关键字:窗口 InvalidComObjectException 创建 单元测试 为什么 | 更新日期: 2023-09-27 18:19:06

在使用MSTest进行单元测试时,我创建了一个WPF窗口。当这个窗口关闭时,Visual Studio显示InvalidComObjectException:

COM object that has been separated from its underlying RCW cannot be used.

[TestMethod]退出后引发,并且堆栈只包含外部代码(不包含InnerException)。这是我的文件:

StackTrace:
       at System.Windows.Input.TextServicesContext.StopTransitoryExtension()
       at System.Windows.Input.TextServicesContext.Uninitialize(Boolean appDomainShutdown)
       at System.Windows.Input.TextServicesContext.TextServicesContextShutDownListener.OnShutDown(Object target, Object sender, EventArgs e)
       at MS.Internal.ShutDownListener.HandleShutDown(Object sender, EventArgs e)
DeclaringType:
    {Name = "TextServicesContext" FullName = "System.Windows.Input.TextServicesContext"}
    Assembly:
        {PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}

下面是创建窗口的代码:

var myWindow = new SomeWindow(errors);
myWindow.ShowDialog();

窗口包含两个ListView,其中包含一些文本元素和复选框

为什么关闭在单元测试中创建的窗口会引发InvalidComObjectException

我是前段时间偶然发现的。如果我没记错的话,这是因为在测试之间,AppDomain的默认Dispatcher没有被正确地清理和重新初始化。

为了解决这个问题,我创建了一个DomainNeedsDispatcherCleanup属性类,它负责Dispatcher的正确设置和拆卸。我一找到它就把它包含在这里,但请注意,我使用的是XUnit,而不是MSTest。

编辑:刚刚找到。给你:

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Threading;
using Xunit;
namespace Boost.Utils.Testing.XUnit.WPF
{
    /// <summary>helful if you stumble upon 'object disconnected from RCW' ComException *after* the test suite finishes,
    /// or if you are unable to start the test because the VS test runner tells you 'Unable to start more than one local run'
    /// even if all tests seem to have finished</summary>
    /// <remarks>only to be used with xUnit STA worker threads</remarks>
    [AttributeUsage(AttributeTargets.Method)]
    public class DomainNeedsDispatcherCleanupAttribute : BeforeAfterTestAttribute
    {
        public override void After(MethodInfo methodUnderTest)
        {
            base.After(methodUnderTest);
            Dispatcher.CurrentDispatcher.InvokeShutdown();
        }
    }
}

哈哈. .因此,正如您所看到的,修复是微不足道的。我不记得了。当然,你只需要InvokeShutdown在你的teardown,它应该是固定的。