I try to write System Tests in NUnit and I want to Invoke the UI using the UI Automation from ms.
For some reason my Invokes fail - I found some hints online that got me to a state where I can write a compiling test but my assertion fails.
Here is a compileable minimal example. My problem is the failing test in the example.
Application XAML
<Application x:Class="InvokeTest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:InvokeTest"
Startup="Application_Startup"/>
Application CS
using System.Windows;
namespace InvokeTest
{
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
var view = new MainWindow();
var viewmodel = new MainWindowViewModel();
view.DataContext = viewmodel;
view.Show();
}
}
}
Window XAML
<Window x:Class="InvokeTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:InvokeTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<TextBox x:Name="MyTextBox" x:FieldModifier="public" Text="{Binding TextProperty, UpdateSourceTrigger=PropertyChanged}" />
</Window>
Window CS
using NUnit.Framework;
using System.Diagnostics;
using System.Threading;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Windows.Controls;
namespace InvokeTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class MainWindowViewModel
{
string textfield;
public string TextProperty
{
get { DebugLog("getter"); return textfield; }
set { textfield = value; DebugLog("setter"); }
}
private void DebugLog(string function)
{
Debug.WriteLine(ToString() + " " + nameof(TextProperty) + " " + function + " was called. value: '" + textfield ?? "<null>" + "'");
}
[TestFixture, Apartment(ApartmentState.STA)]
public class WPFTest
{
MainWindow view;
MainWindowViewModel viewmodel;
[SetUp]
public void SetUp()
{
view = new MainWindow();
viewmodel = new MainWindowViewModel();
view.DataContext = viewmodel;
}
[Test]
public void SetTextBox_NoAutomation()
{
string expected = "I want to set this";
view.MyTextBox.Text = expected;
Assert.AreEqual(expected, viewmodel.TextProperty);
/*
Test Name: SetTextBox_NoAutomation
Test Outcome: Failed
Result Message:
Expected: "I want to set this"
But was: null
*/
}
[Test]
public void SetTextBox_UIAutomation()
{
string expected = "I want to set this";
SetValue(view.MyTextBox, expected);
Assert.AreEqual(expected, viewmodel.TextProperty);
/*
Test Name: SetTextBox_UIAutomation
Test Outcome: Failed
Result Message:
Expected: "I want to set this"
But was: null
*/
}
private static void SetValue(TextBox textbox, string value)
{
TextBoxAutomationPeer peer = new TextBoxAutomationPeer(textbox);
IValueProvider provider = peer.GetPattern(PatternInterface.Value) as IValueProvider;
provider.SetValue(value);
}
}
}
}
EDIT #1: @Nkosi pointed out that there was a binding failure in my xaml
EDIT #2: Added a bit of boiler to enable manual testing and also added a usecase that shows behaviour without uiautomation. That is just a sidenote, uiautomation is the core of this question.
Actually you can call the TextBox.Text Property.
view.MyTextBox.Text = expected;
In your view you are also binding to Text
property on your view model while the view model in your test has a MyTextBox
property. One or the other needs to be updated to match.
public class MainWindowViewModel
{
public string Text { get; set; }
}
[TestFixture, Apartment(ApartmentState.STA)]
public class WPFTest
{
[Test]
public void SetTextBox()
{
//Arrange
var expected = "I want to set this";
var view = new MainWindow();
var viewmodel = new MainWindowViewModel();
view.DataContext = viewmodel;
//Act
view.MyTextBox.Text = expected;
//Assert
Assert.AreEqual(expected, viewmodel.Text);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With