2010-11-23 25 views
7

que tienen esta función auxiliar estática:¿Cómo puedo probar la unidad de algo que utiliza VisualTreeHelper?

public static DependencyObject GetParentObject(DependencyObject child) 
    { 
     if (child == null) return null; 
     ContentElement contentElement = child as ContentElement; 

     if (contentElement != null) 
     { 
      var parent = ContentOperations.GetParent(contentElement); 
      if (parent != null) return parent; 

      var fce = contentElement as FrameworkContentElement; 
      return fce != null ? fce.Parent : null; 
     } 

     //if it's not a ContentElement, rely on VisualTreeHelper 
     return VisualTreeHelper.GetParent(child); 
    } 

Funciona en una aplicación real, pero estoy tratando de escribir algunas pruebas unitarias para ello. Aquí está mi primer intento:

[Test] 
    public void GetParentObject_returns_immediate_parent() 
    { 
     var contentControl = new ContentControl(); 
     var textBox = new TextBox(); 

     contentControl.BeginInit(); 
     contentControl.Content = textBox; 
     contentControl.EndInit(); 

     var result = UIHelper.GetParentObject(textBox); 
     Assert.AreSame(contentControl, result); 
    } 

Desafortunadamente falla porque VisualTreeHelper está volviendo nula. ¿Cómo puedo simular un árbol visual que funcionará?

Respuesta

2

Es por esto que la estática es problemática.

Puede abstraer la funcionalidad detrás de una interfaz y crear una implementación predeterminada que use el método estático. A continuación, puede utilizar la inyección de dependencia, lo que hace que esta prueba de la unidad sea trivial: se burle de la dependencia de IVisualTreeHelper o despliegue su propia implementación de stub que puede configurar para devolver cualquier valor que asigne.

public class Foo 
{ 
    static IVisualTreeHelper visualTreeHelper; 

    static Foo() 
    { 
     Foo.visualTreeHelper = new FrameworkVisualTreeHelper(); 
    } 

    public Foo(IVisualTreeHelper visualTreeHelper) 
    { 
     Foo.visualTreeHelper = visualTreeHelper; 
    } 

    public static DependencyObject GetParentObject(DependencyObject child) 
    { 
     if (child == null) return null; 
     ContentElement contentElement = child as ContentElement; 

     if (contentElement != null) 
     { 
      var parent = ContentOperations.GetParent(contentElement); 
      if (parent != null) return parent; 

      var fce = contentElement as FrameworkContentElement; 
      return fce != null ? fce.Parent : null; 
     } 

     //if it's not a ContentElement, rely on the IVisualTreeHelper 
     return visualTreeHelper.GetParent(child); 
    } 
} 

public interface IVisualTreeHelper 
{ 
    DependencyObject GetParent(DependencyObject reference); 
} 

public class FrameworkVisualTreeHelper : IVisualTreeHelper 
{ 
    public DependencyObject GetParent(DependencyObject reference) 
    { 
     return VisualTreeHelper.GetParent(reference); 
    } 
} 

Obviamente, es posible que tenga que añadir otros métodos VisualTreeHelper a su interfaz y aplicación por defecto, si está usando otros métodos en otros lugares.

Todavía no está completamente limpio porque la unidad que está probando es en sí misma estática, y va a encontrarse exactamente con el mismo problema cuando intente probar la unidad de cualquier clase que dependa de los métodos estáticos de su clase UIHelper .

-1

Para simular un árbol visual, tendrá que crear y representar uno. Por lo tanto, tendrá que crear una ventana real, que no es particularmente ideal para una prueba unitaria.

2

Sobre la base de esta respuesta aquí en printing documents via Wpf-controls and convert to XPS me ocurrió con el siguiente método de extensión para crear el árbol visual. Funciona bien dentro de NUnit sin STA-thread ni nada.

/// <summary> 
/// Render a UIElement such that the visual tree is generated, 
/// without actually displaying the UIElement 
/// anywhere 
/// </summary> 
public static void CreateVisualTree(this UIElement element) 
{ 
    var fixedDoc = new FixedDocument(); 
    var pageContent = new PageContent(); 
    var fixedPage = new FixedPage(); 
    fixedPage.Children.Add(element); 
    pageContent.ToMaybeOf<IAddChild>().Do(c => c.AddChild(fixedPage)); 
    fixedDoc.Pages.Add(pageContent); 

    var f = new XpsSerializerFactory(); 
    var w = f.CreateSerializerWriter(new MemoryStream()); 
    w.Write(fixedDoc); 
} 

Tenga en cuenta que

  • la otra respuesta utiliza una API del Reach-DLL que no se parece a la API que estoy viendo. Asumo que hay diferencias entre las versiones de .NET Framework 3.5 y 4.0
  • la materia ToMaybeOf significa básicamente para tratar pageContent como IAddChild y hacer una acción en esa interfaz
  • Esto le no trabajo con un elemento de tipo ventana ya que el elemento se agrega esencialmente como un elemento secundario a Visual y Window se quejará amargamente de esto.
+0

yo echo 'pageContent' a' IAddChild' y realiza la operación directamente, en lugar de confiar en el 'ToMaybeOf' y' Do': '((IAddChild) PageContent) .AddChild (FixedPage);' –

Cuestiones relacionadas