IInvokeProvider.Invoke 在 NUnit 测试中

IInvokeProvider.Invoke in NUnit Test

我有一个 WPF 用户控件,我正在为使用 NUnit 编写一些单元测试。其中一项测试在 window 上显示控件并单击控件上的按钮。之后它会确认收到了正确的结果。

使用 RaisedEvents 它看起来像这样并且可以正常工作。

MyButton.RaiseEvent(buttonArgs);
Assert.AreEqual(expected, actual);

我正在尝试使用自动化框架做同样的事情。类似于:

ButtonAutomationPeer peer = new ButtonAutomationPeer(MyButton);
IInvokeProvider invokeProv = (IInvokeProvider)(peer.GetPattern(PatternInterface.Invoke));
invokeProv.Invoke();
Assert.AreEqual(expected, actual);

现在在这种情况下,断言失败(正如预期的那样),因为 Invoke 是异步调用的,并且在断言时尚未发生。

我希望我可以通过在单独的线程上调用 Invoke 并等待它完成来解决这个问题。

Thread thread = new Thread(invokeProv.Invoke);
thread.Start();
thread.Join();

然而这仍然失败。就像睡觉一样:

invokeProv.Invoke();
Thread.Sleep(1000);

显示对话框并强制用户继续,但确实有效。

invokeProv.Invoke();
System.Windows.MessageBox.Show("");

所以我认为我需要做一些设置才能让事情按照我喜欢的方式运行。也许为调度程序或 Window 设置一个单独的线程。我敢肯定有这样的例子,但我似乎没有在寻找正确的关键词。请注意,NUnit 要求我 运行 使用 RequiresSTA 属性进行单元测试。

我认为你的结论是正确的。 IInvokeProvider.Invoke 是异步的,就像 Dispatcher.BeginInvoke 是异步的一样。它只是将消息放入队列中以供调度程序处理。但是,在显示消息框之前,您不会启动线程的调度程序。您可能需要类似 this 的东西来处理测试线程中的调度程序操作。

public static void DoEvents()
{
    DispatcherFrame frame = new DispatcherFrame();
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
            new DispatcherOperationCallback(ExitFrame), frame);
    Dispatcher.PushFrame(frame);
}

public static object ExitFrame(object f)
{
    ((DispatcherFrame)f).Continue = false;
    return null;
}

可以这样使用:

ButtonAutomationPeer peer = new ButtonAutomationPeer(MyButton);
IInvokeProvider invokeProv = (IInvokeProvider)(peer.GetPattern(PatternInterface.Invoke));
invokeProv.Invoke();
DoEvents();
Assert.AreEqual(expected, actual);