2010-02-19 13 views
7

Todavía estoy teniendo comportamientos similares en general, y no entiendo cómo escribir una prueba de unidad para uno.unidad prueba un comportamiento adjunto wpf

He pegado un código debajo del marco Cinch de Sacha Barber que permite que una ventana se cierre mediante el comportamiento adjunto. ¿Puede alguien mostrarme un ejemplo de prueba de unidad?

Gracias!
Berryl

#region Close 

    /// <summary>Dependency property which holds the ICommand for the Close event</summary> 
    public static readonly DependencyProperty CloseProperty = 
     DependencyProperty.RegisterAttached("Close", 
      typeof(ICommand), typeof(Lifetime), 
       new UIPropertyMetadata(null, OnCloseEventInfoChanged)); 

    /// <summary>Attached Property getter to retrieve the CloseProperty ICommand</summary> 
    public static ICommand GetClose(DependencyObject source) 
    { 
     return (ICommand)source.GetValue(CloseProperty); 
    } 

    /// <summary>Attached Property setter to change the CloseProperty ICommand</summary> 
    public static void SetClose(DependencyObject source, ICommand command) 
    { 
     source.SetValue(CloseProperty, command); 
    } 

    /// <summary>This is the property changed handler for the Close property.</summary> 
    private static void OnCloseEventInfoChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     var win = sender as Window; 
     if (win == null) return; 

     win.Closing -= OnWindowClosing; 
     win.Closed -= OnWindowClosed; 

     if (e.NewValue == null) return; 

     win.Closing += OnWindowClosing; 
     win.Closed += OnWindowClosed; 
    } 

    /// <summary> 
    /// This method is invoked when the Window.Closing event is raised. 
    /// It checks with the ICommand.CanExecute handler 
    /// and cancels the event if the handler returns false. 
    /// </summary> 
    private static void OnWindowClosing(object sender, CancelEventArgs e) 
    { 
     var dpo = (DependencyObject)sender; 
     var ic = GetClose(dpo); 
     if (ic == null) return; 

     e.Cancel = !ic.CanExecute(GetCommandParameter(dpo)); 
    } 

    /// <summary> 
    /// This method is invoked when the Window.Closed event is raised. 
    /// It executes the ICommand.Execute handler. 
    /// </summary> 
    static void OnWindowClosed(object sender, EventArgs e) 
    { 
     var dpo = (DependencyObject)sender; 
     var ic = GetClose(dpo); 
     if (ic == null) return; 

     ic.Execute(GetCommandParameter(dpo)); 
    } 

    #endregion 

Respuesta

5

Es probable que utilice un lambda en su ICommand utilizando un DelegateCommand o una RelayCommand. Existen múltiples implementaciones de estos en todo el lugar y Cinch puede tener algo similar. versión muy simple (como ejemplo, no sirve para su uso en producción):

public class DelegateCommand : ICommand { 
    private Action _execute = null; 

    public void Execute(object parameter) { 
     _execute(); 
    } 

    public DelegateCommand(Action execute) { 
     _execute = execute; 
    } 

    #region stuff that doesn't affect functionality 
    public bool CanExecute(object parameter) { 
     return true; 
    } 
    public event EventHandler CanExecuteChanged { 
     add { } 
     remove { } 
    } 
    #endregion 
} 

Luego, su cuerpo de prueba podría ser algo como esto:

bool wascalled = false; 

var execute = new DelegateCommand(
    () => { 
     wascalled = true; 
    }); 

var window = new Window(); 
SomeClass.SetClose(window, execute); 

// does the window need to be shown for Close() to work? Nope. 

window.Close(); 

AssertIsTrue(wascalled); 

Este es un ejemplo sobre-simplificado. Por supuesto, hay otras pruebas que deseará realizar, en cuyo caso debe crear o encontrar una implementación más completa de DelegateCommand que también implemente correctamente CanExecute, entre otras cosas.

+0

cinch va un paso más allá con el RelayCommand al hornear su llamada prueba en una propiedad bool CommandSucceeded. Tu publicación es útil para forzar que SetClose siga siendo un setter de propiedades al final del día, ¡incluso si no se parece a los más simples establecedores de propiedades normales de C#! Esa es una de las cosas que no estaba viendo y aún no es intuitiva para mí sobre el comportamiento DP/adjunto. Cheers – Berryl

+0

Sí. Cuando se compila, se llaman esos métodos Get/Set estáticos. Lo mismo con DP: omite el contenedor de propiedades y llama directamente a 'SetValue' /' GetValue' en 'DependencyObject'. Es bueno saber de eso en Cinch. No es uno que haya leído aún. –

3

DependencyProperty cambiar y el valor coacción, tanto por sus propias miradas como 'Dependencias imposibles' para mí. Tener referencia a Window hace las cosas aún más complicadas. Creo que me gustaría ir con Humble Object pattern aquí ...

+0

Realmente puedo vivir con la ventana en este caso, pero ese es un enlace interesante. ¿Puedes ilustrar cómo aplicarías el Patrón de objetos humildes en este caso? Cheers – Berryl