2008-12-01 20 views
10

Estoy tratando de probar de forma unitaria mis conexiones de datos de WPF utilizando la prueba provista por Microsoft Team System. Me gustaría poder probar los enlaces sin mostrar la ventana porque la mayoría de mis pruebas serán para controles de usuario y no en una ventana. ¿Es esto posible o hay una mejor manera de hacerlo? El siguiente código funciona si muestro la ventana, pero si no lo hago, los enlaces no se actualizan.Prueba de unidad Enlaces de WPF

  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 

Respuesta

2

Shane, si lo que realmente te preocupa es una ruptura de enlace en silencio, deberías ver redirigir las trazas vinculantes hacia un lugar que puedas examinar. Yo empezaría aquí:

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

Aparte de eso, estoy de acuerdo con Gishu que las consolidaciones no son buenos candidatos para las pruebas unitarias, debido principalmente a la automagic pasando Gishu que se menciona en el "Epílogo". En su lugar, concéntrese en asegurarse de que la clase subyacente se comporte correctamente.

Tenga en cuenta, también, que se puede obtener incluso más robusto trazas utilizando la clase PresentationTraceSources:

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

Espero que ayude!

1

Eyeball it.
Este tipo de marcado declarativo rara vez se rompe ... a menos que alguien entre en manual y lo estropee. Incluso entonces, puedes arreglarlo en minutos. En mi humilde opinión, el costo de escribir tales pruebas supera con creces los beneficios.

Actualización [Dec3,08]: Bien entonces.
La prueba solo está probando que el cuadro de texto tiene el valor "Nombre" como la propiedad Ruta del enlace. Si cambio/refactorizo ​​FirstName a JustName en el objeto de fuente de datos real, la prueba aún pasaría, ya que está probando contra un tipo anónimo. (Prueba de verde cuando el código roto - TDD antipatrón: The Liar) Si su objetivo es verificar que FirstName se ha especificado en XAML,

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

Si realmente tiene que coger fijaciones rotas a través de pruebas de unidad (y no hacer quiere mostrar la IU), use la fuente de datos real ... luchó por un tiempo y se le ocurrió esto.

[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); 
} 

Epílogo: hay algo de real covert stuff ocurriendo en la llamada a Window.Show(). De alguna manera mágicamente configura la propiedad DataItem después de la cual el enlace de datos comienza a funcionar.

// before show 
bindingExpr.DataItem => null 
bindingExpr.Status => BindingStatus.Unattached 

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

Una vez que la unión es activo, supongo que se puede forzar cambios de cuadro de texto a través de un código como éste ..

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

Una vez más, la voz de mi renuencia contra de este enfoque. Hacer que NUnit se ejecute en STA fue una molestia ...

+2

Si son vinculantes a las propiedades de una clase, y refactorizar la clase, la xaml todavía compilar, pero no es una excepción será lanzada y nuestra aplicación va a la función no más correctamente como las fijaciones será incorrecta. Esto ya ha sido un problema para nosotros y por eso estamos buscando una solución. – NotDan

0

puedes probar Guia. Con él puede probar su UserControl y verificar si el enlace de datos es correcto. Tienes que mostrar la ventana sin embargo.

Aquí hay un ejemplo.Inicia una nueva instancia de UserControl y establece su DataContext y luego verifica si el cuadro de texto está configurado con el valor correcto.

[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(); 
    } 
1

Asesoramiento combinado Encontré varias publicaciones SO Escribí la siguiente clase que funciona muy bien para probar enlaces WPF.

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); 
     } 
    } 
} 
4

bien en busca de una solución para convertir WPF errores en la unión excepción, me di cuenta de que también se puede utilizar en un proyecto de prueba unitaria.

La técnica es muy sencilla:

  1. derivar una TraceListener que lanza en lugar de entrar
  2. Añadir que escucha a PresentationTraceSources.DataBindingSource

Por favor ver el complete solution on GitHub, que incluye un proyecto de prueba unitaria.

Failed test in Visual Studio