【问题标题】:unit test an attached behavior wpf单元测试附加行为 wpf
【发布时间】:2011-01-18 19:37:55
【问题描述】:

我仍然在探索一般的附加行为,并且不知道如何为一个人编写单元测试。

我在下面粘贴了一些来自 Sacha Barber 的 Cinch 框架的代码,该框架允许通过附加行为关闭窗口。有人可以给我看一个示例单元测试吗?

谢谢!
浆果

    #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

【问题讨论】:

    标签: wpf unit-testing attachedbehaviors


    【解决方案1】:

    您可能会在 ICommand 中使用 lambda,使用 DelegateCommandRelayCommand。这些的多种实现到处都存在,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 上更进一步,将您的 wascall 测试烘焙到 CommandSucceeded bool 属性中。您的帖子有助于强制执行 SetClose 在一天结束时仍然是一个属性设置器,即使它看起来不像更简单的普通 C# 属性设置器!这是我没有看到的事情之一,对我来说还不是关于 DP/附加行为的直觉。干杯
    • 是的。编译时,会调用那些静态的 Get/Set 方法。与 DP 相同:它跳过属性包装器并直接在 DependencyObject 上调用 SetValue/GetValue。很高兴在 Cinch 听到这个消息。这不是我仔细阅读过的。
    【解决方案2】:

    DependencyProperty 改变和价值强制对我来说看起来像是“不可能的依赖”。在那里引用 Window 会使事情变得更加棘手。我想我会在这里使用Humble Object pattern...

    【讨论】:

    • 在这种情况下我实际上可以使用窗口,但这是一个有趣的链接。您能否说明在这种情况下如何应用 Humble Object 模式?干杯
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-24
    • 2011-06-28
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多