【问题标题】:Running a WPF dialog from a test从测试运行 WPF 对话框
【发布时间】:2013-11-04 02:35:22
【问题描述】:

当我在单元测试中运行 ShowDialog 调用时,我得到一个

System.Windows.Markup.XamlParseException:当前 SynchronizationContext 不能用作任务调度程序。

从 main 运行正常。我意识到这不是测试仪的正常使用,但是能够选择一个对话框并单击一个按钮以使用测试数据运行它以查看对话框是否有效是很有价值的。但是这个错误阻止我运行它。

在“正确”线程上运行对话框代码是否有技巧?

这是单元测试代码:

[Fact]
static public void Draw2()
{
  var uiThread = new Thread(Draw20);
  uiThread.SetApartmentState(ApartmentState.STA);
  uiThread.Start();
  // Wait for the UI thread to finish
  uiThread.Join();
}
  static void Draw20()
  {
    ModernUIApp1.MainWindow window = new MainWindow();

    System.Windows.Forms.Integration
      .ElementHost
      .EnableModelessKeyboardInterop(window);
    window.ShowDialog();
    window = null;
  }

窗口代码: >

    <mui:ModernWindow.MenuLinkGroups>
    <mui:LinkGroup DisplayName="welcome">
      <mui:LinkGroup.Links>
        <mui:Link DisplayName="home" Source="/Pages/Home.xaml" />
        <mui:Link DisplayName="my page" Source="/Pages/BasicPage.xaml" />
      </mui:LinkGroup.Links>
    </mui:LinkGroup>
    <mui:LinkGroup DisplayName="settings" GroupName="settings">
            <mui:LinkGroup.Links>
                <mui:Link DisplayName="software" Source="/Pages/Settings.xaml" />
            </mui:LinkGroup.Links>
        </mui:LinkGroup>
    </mui:ModernWindow.MenuLinkGroups>

    <mui:ModernWindow.TitleLinks>
        <mui:Link DisplayName="settings" Source="/Pages/Settings.xaml" />
    </mui:ModernWindow.TitleLinks>
</mui:ModernWindow>

【问题讨论】:

  • 哪些代码会导致这种情况?也许你可以发布你的代码和你的单元测试细节。
  • 您是否在 Google 上搜索过“当前 SynchronizationContext 可能无法用作任务调度程序”?
  • 是的,我发现讨论是围绕任务对象进行的。对我的理解没有帮助。
  • 此异常源自哪个线程?您的测试线程或您正在创建的 UI 线程?另外,您使用的是哪个单元测试框架?哪个测试运行器?
  • UI 线程获取异常。我正在使用带有 xunit.net 的 Visual Studio 嵌入式测试运行器。

标签: c# wpf xunit.net modern-ui


【解决方案1】:

为了在单元测试中显示 WPF UI,您需要生成一个新线程,确保它是 single-threaded apartment (STA),从该线程创建 UI,显示对话框,然后将结果编组回单元测试线程。

var uiThread = new Thread(MyCreateAndShowUIFunction);
uiThread.SetApartmentState(ApartmentState.STA);
uiThread.Start();

...

// Wait for the UI thread to finish
uiThread.Join();

总的来说,单元测试并非旨在实际启动 UI。那将是一个集成测试,甚至是一个编码的 UI 测试。

【讨论】:

  • 我试过这段代码,但同样的问题出现在新的对话线程中。现在关于您的评论,请启发我:集成测试或编码 ui 测试应该使用什么工具,为什么它比单元测试器更好?
  • 向我们展示您正在使用的代码;如果您生成一个 STA 线程来创建和处理 UI,您应该能够在单元测试中测试 UI。
  • 那么当您创建主窗口和所有其他 UI 内容时?你需要把它放在 MyCreateAndShowUIFunction 里面,就像我上面展示的那样。
  • 我做了犹大,它没有帮助。仍然是 SynchronozationContext 错误。
【解决方案2】:

搜索了这个错误,看起来你可能需要set your own sync context

[SetUp]
public void TestSetUp()
{
  SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}

【讨论】:

    【解决方案3】:

    我怀疑这是您的单元测试运行程序或对话框中的某些代码的问题,因为我可以使用 ReSharper 的 xUnit 运行程序很好地运行您的代码。我的对话框只包含一个设置DialogResult的按钮,并且测试完成,没有任何异常。

    在创建对话框之前,您可以尝试在您的 UI 线程上运行

    SynchronizationContext.SetSynchronizationContext(
        new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher)
    );
    

    如果这不起作用,请尝试将其与 @JudahHimango 的为测试线程创建 SynchronizationContext 的答案结合起来。

    【讨论】:

    • 我试过你在 UI 线程上建议的代码,没有运气。至于你的测试,我也可以让一个按钮工作。当我将 Home.xaml 页面添加到示例时失败。
    • 嗯,这肯定会缩小范围。您是否调用了该页面中使用System.Threading.Tasks API 或async/await 的任何代码,可能是间接调用?另外,您是否尝试将我的想法与 Judah 为测试线程设置 SynchronizationContext.SetSynchronizationContext(new SynchronizationContext()); 的想法结合起来?
    猜你喜欢
    • 2021-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-09
    • 1970-01-01
    • 2018-01-23
    • 2017-12-10
    • 2011-05-31
    相关资源
    最近更新 更多