WPF中如何对附加属性进行单元测试

7

我仍在学习关于附加行为的知识,并且不知道如何编写一个单元测试。

下面是来自Sacha Barber的Cinch框架的代码,可以通过附加行为关闭窗口。有人能给我展示一个例子单元测试吗?

谢谢!
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
2个回答

5

你可能会在使用DelegateCommand或者RelayCommand的时候,在你的ICommand中使用lambda表达式。这些实现在各个地方都有,并且Cinch可能也有类似的东西。这里提供一个非常简单的版本(作为示例,不适用于生产环境):

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
}

那么您的测试主体可能看起来像这样:
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 );

这只是一个过于简化的例子。当然,您可能需要执行其他测试,在这种情况下,您应该创建或查找更完整的DelegateCommand实现,该实现还正确地实现了CanExecute等其他功能。


Cinch通过RelayCommand更进一步,将您的wascalled测试嵌入到CommandSucceeded布尔属性中。您的帖子有助于强制执行SetClose仍然是属性设置器,即使它看起来不像简单的常规C#属性设置器!这是我在DP /附加行为方面尚未看到并且不直观的事情之一。干杯 - Berryl
是的。编译后,这些静态的Get/Set方法会被调用。DP也是一样:它跳过属性包装器,直接在DependencyObject上调用SetValue/GetValue。很高兴听到Cinch中有这个功能。这是我还没有研究过的一个功能。 - Joel B Fant

3

对于我来说,DependencyProperty的更改和值强制执行本身就像是“不可能的依赖项”。这里还涉及到对Window的引用,使事情变得更加棘手。我认为我会采用谦虚对象模式...


我实际上可以接受这种情况下的窗口,但那是一个有趣的链接。你能说明在这种情况下如何应用“谦虚对象模式”吗?干杯 - Berryl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接