Reputation: 3135
I have a WPF user control that I am writing some unit tests for using NUnit. One of the tests displays the control on a window and clicks a button on the control. After which it looks to confirm the correct result was received.
Using RaisedEvents it looks something like this and works correctly.
MyButton.RaiseEvent(buttonArgs);
Assert.AreEqual(expected, actual);
I am trying to do the same thing using the automation framework. Something like:
ButtonAutomationPeer peer = new ButtonAutomationPeer(MyButton);
IInvokeProvider invokeProv = (IInvokeProvider)(peer.GetPattern(PatternInterface.Invoke));
invokeProv.Invoke();
Assert.AreEqual(expected, actual);
Now in this case the assert fails (as expected) because Invoke is called asynchronously and has not yet occurred at the time of the assertion.
I was hoping that I could resolve this by calling Invoke on a separate thread and waiting for it to complete.
Thread thread = new Thread(invokeProv.Invoke);
thread.Start();
thread.Join();
However this still fails. As does just sleeping:
invokeProv.Invoke();
Thread.Sleep(1000);
Showing a dialog and forcing the user to continue, does however work.
invokeProv.Invoke();
System.Windows.MessageBox.Show("");
So I think there is some sort of setup I need to do to get things to behave the way I like. Perhaps setting up a separate thread for the dispatcher, or the Window. I'm sure there are examples of this out there, but I seem to not be searching on the right key words. Note that NUnit is requiring me to run my unit tests with the RequiresSTA attribute.
Upvotes: 1
Views: 526
Reputation: 40818
I think your conclusion is correct. IInvokeProvider.Invoke
is async the same way Dispatcher.BeginInvoke
is async. It just puts a message into the queue for the dispatcher to process. However you are not starting the thread's dispatcher until you show the message box. You probably want something like this to process the dispatcher operations in the test thread.
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;
}
Which can be used like so:
ButtonAutomationPeer peer = new ButtonAutomationPeer(MyButton);
IInvokeProvider invokeProv = (IInvokeProvider)(peer.GetPattern(PatternInterface.Invoke));
invokeProv.Invoke();
DoEvents();
Assert.AreEqual(expected, actual);
Upvotes: 2