Unit test WPF bindings

I am trying to use unit test my data in WPF using a test case provided by Microsoft Team System. I would like to be able to check the bindings without showing the window, because most of my tests will be for user controls, and not actually in the window. Is this possible or is there a better way to do this? The code below works if I show this window, but if this does not happen, the bindings will not be updated.

Window1_Accessor target = new Window1_Accessor(); UnitTestingWPF.Window1_Accessor.Person p = new UnitTestingWPF.Window1_Accessor.Person() { FirstName = "Shane" }; Window1 window = (target.Target as Window1); window.DataContext = p; //window.Show(); //Only Works when I actually show the window //Is it possible to manually update the binding here, maybe? Is there a better way? Assert.AreEqual("Shane", target.textBoxFirstName.Text); //Fails if I don't Show() the window because the bindings aren't updated 
+10
unit-testing data-binding wpf binding
Dec 01 '08 at 15:44
source share
5 answers

Shane, if what you really care about is a mandatory violation of silence, you should look at redirecting the binding traces to where you can study. I would start here:

http://blogs.msdn.com/mikehillberg/archive/2006/09/14/WpfTraceSources.aspx

In addition, I agree with Guiche that bindings are not good candidates for unit testing, mainly because Giga, mentioned in the Epilogue, was automatically published. Instead, focus on making sure that the base class behaves correctly.

Note that you can get even more reliable traces using the PresentationTraceSources class:

http://msdn.microsoft.com/en-us/library/system.diagnostics.presentationtracesources.aspx

Hope this helps!

+2
Dec 03 '08 at 15:17
source share

When looking for a solution to convert WPF binding errors to an exception, I realized that it could also be used in a unit test project.

The technique is very simple:

  • Print TraceListener , which returns instead of writing
  • Add this listener to PresentationTraceSources.DataBindingSource

Please see the complete solution on GitHub , it includes the unit test project.

Failed test in Visual Studio

+4
Oct 26 '13 at 18:45
source share

Eyeball it.
Such declarative markup rarely breaks. If someone is not in the manual and does not spin it. Even then you can fix it in a few minutes. IMHO, the cost of writing such tests far exceeds the benefits.

Update [Dec3.08]: Then, fine.
The test simply verifies that the text field is set to "FirstName" as the binding's Path property. If I change / refactor FirstName to JustName in the actual data source object, the test will pass anyway, since it is testing an anonymous type. (The green test when breaking the code is TDD Antipattern: The Liar) If your goal is to verify that FirstName is specified in XAML,

 Assert.AreEqual("FirstName", txtBoxToProbe.GetBindingExpression(TextBox.TextProperty).ParentBinding.Path.Path); 

If you really have to break broken bindings with unit tests (and don't want to show the user interface), use a real data source ... struggling for a while and came up with this.

 [Test] public void TestTextBoxBinding() { MyWindow w = new MyWindow(); TextBox txtBoxToProbe = w.TextBox1; Object obDataSource = w; // use 'real' data source BindingExpression bindingExpr = BindingOperations.GetBindingExpression(txtBoxToProbe, TextBox.TextProperty); Binding newBind = new Binding(bindingExpr.ParentBinding.Path.Path); newBind.Source = obDataSource; txtBoxToProbe.SetBinding(TextBox.TextProperty, newBind); Assert.AreEqual("Go ahead. Change my value.", txtBoxToProbe.Text); } 

Afterword: There real hidden material happens when Window.Show() called. This somehow magically sets the DataItem property, after which the data binding starts working.

 // before show bindingExpr.DataItem => null bindingExpr.Status => BindingStatus.Unattached // after show bindingExpr.DataItem => {Actual Data Source} bindingExpr.Status => BindingStatus.Active 

Once the binding is active, I think you can force text fields to be updated using this code.

 txtBoxToProbe.GetBindingExpression(TextBox.TextProperty).UpdateTarget(); 

Once again, I express my reluctance against this approach. Getting NUnit to run in the STA was a pain.

+1
Dec 01 '08 at 17:58
source share

Combining the tips I met in several SO posts, I wrote the following class, which works very well to test WPF bindings.

 public static class WpfBindingTester { /// <summary>load a view in a hidden window and monitor it for binding errors</summary> /// <param name="view">a data-bound view to load and monitor for binding errors</param> public static void AssertBindings(object view) { using (InternalTraceListener listener = new InternalTraceListener()) { ManualResetEventSlim mre = new ManualResetEventSlim(false); Window window = new Window { Width = 0, Height = 0, WindowStyle = WindowStyle.None, ShowInTaskbar = false, ShowActivated = false, Content = view }; window.Loaded += (_, __) => mre.Set(); window.Show(); mre.Wait(); window.Close(); Assert.That(listener.ErrorMessages, Is.Empty, listener.ErrorMessages); } } /// <summary>Is the test running in an interactive session. Use with Assume.That(WpfBindingTester.IsAvailable) to make sure tests only run where they're able to</summary> public static bool IsAvailable { get { return Environment.UserInteractive && Process.GetCurrentProcess().SessionId != 0; } } private class InternalTraceListener : TraceListener { private readonly StringBuilder _errors = new StringBuilder(); private readonly SourceLevels _originalLevel; public string ErrorMessages { get { return _errors.ToString(); } } static InternalTraceListener() { PresentationTraceSources.Refresh(); } public InternalTraceListener() { _originalLevel = PresentationTraceSources.DataBindingSource.Switch.Level; PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error; PresentationTraceSources.DataBindingSource.Listeners.Add(this); } public override void Write(string message) {} public override void WriteLine(string message) { _errors.AppendLine(message); } protected override void Dispose(bool disposing) { PresentationTraceSources.DataBindingSource.Listeners.Remove(this); PresentationTraceSources.DataBindingSource.Switch.Level = _originalLevel; base.Dispose(disposing); } } } 
+1
Jul 13 '12 at 9:16
source share

you can try guia . With it, you can test your UserControl and verify that the data binding is correct. You should show a window, though.

Here is an example. It starts a new instance of your UserControl and sets its DataContext, and then checks if the text field is set to the desired value.

  [TestMethod] public void SimpleTest() { var viewModel = new SimpleControlViewModel() {TextBoxText = "Some Text"}; customControl = CustomControl.Start<SimpleUserControl>((control) => control.DataContext = viewModel); Assert.AreEqual("Some Text", customControl.Get<TextBox>("textbox1").Value); customControl.Stop(); } 
0
Nov 04 '10 at 19:13
source share



All Articles