wpf - 在带有 WPF 的 MVVM 中,如何对 ViewModel 和 View 之间的链接进行单元测试

标签 wpf unit-testing model-view-controller mvvm

在 MVVM 中,通过数据绑定(bind)将 View 连接到 ViewModel 是很正常的。

因此,如果数据绑定(bind)到的模型对象之一的属性名称发生更改,则不会出现编译器错误。

当编译器无法阻止错误时,我接下来想到的是“UnitTest”,但是

How do you unit test this without spending forever writing a GUI test?

是否有一个系统可以检查我可以在单元测试中调用的所有绑定(bind)属性是否有效(无需运行 UI)?

我正在寻找能够获取 View ,然后循环所有 WPF 控件的东西,对于每个 WPF 控件,它将查看所​​有绑定(bind)并检查它们是否有效。

<小时/>

顺便说一句,有一些关于如何使 OnPropertyChanged 安全和/或如何测试它的好问题(但完成这些问题后,就进入了 WPF View 的级别。)

<小时/>

我对这个问题给予了悬赏,因为一定有人认真思考过这个问题并提出了解决方案。

最佳答案

我想我已经想出了一些可以使用简单反射来工作的东西,并改编了我过去使用过的一些代码(FindBindingsRecursively 方法的代码是由 Martin Bennedik 编写的,如下所示他的 Enterprise WPF Validation Control 的一部分):

[TestMethod]
public void CheckWpfBindingsAreValid()
{
    // instansiate the xaml view and set DataContext
    var yourView = new YourView(); 
    yourView.DataContext = YourViewModel;

    FindBindingsRecursively(yourView,
            delegate(FrameworkElement element, Binding binding, DependencyProperty dp)
            {
                var type = yourView.DataContext.GetType();

                // check that each part of binding valid via reflection
                foreach (string prop in binding.Path.Path.Split('.'))
                {
                    PropertyInfo info = type.GetProperty(prop);
                    Assert.IsNotNull(info);
                    type = info.PropertyType;
                }
    });
}

private delegate void FoundBindingCallbackDelegate(FrameworkElement element, Binding binding, DependencyProperty dp);

private void FindBindingsRecursively(DependencyObject element, FoundBindingCallbackDelegate callbackDelegate)
{
    // See if we should display the errors on this element
    MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Static |
                BindingFlags.Public |
                BindingFlags.FlattenHierarchy);

    foreach (MemberInfo member in members)
    {
        DependencyProperty dp = null;

        // Check to see if the field or property we were given is a dependency property
        if (member.MemberType == MemberTypes.Field)
        {
            FieldInfo field = (FieldInfo)member;
            if (typeof(DependencyProperty).IsAssignableFrom(field.FieldType))
            {
                dp = (DependencyProperty)field.GetValue(element);
            }
        }
        else if (member.MemberType == MemberTypes.Property)
        {
            PropertyInfo prop = (PropertyInfo)member;
            if (typeof(DependencyProperty).IsAssignableFrom(prop.PropertyType))
            {
                dp = (DependencyProperty)prop.GetValue(element, null);
            }
        }

        if (dp != null)
        {
            // Awesome, we have a dependency property. does it have a binding? If yes, is it bound to the property we're interested in?
            Binding bb = BindingOperations.GetBinding(element, dp);
            if (bb != null)
            {
                // This element has a DependencyProperty that we know of that is bound to the property we're interested in. 
                // Now we just tell the callback and the caller will handle it.
                if (element is FrameworkElement)
                {
                    callbackDelegate((FrameworkElement)element, bb, dp);
                }
            }
        }
    }

    // Now, recurse through any child elements
    if (element is FrameworkElement || element is FrameworkContentElement)
    {
        foreach (object childElement in LogicalTreeHelper.GetChildren(element))
        {
            if (childElement is DependencyObject)
            {
                FindBindingsRecursively((DependencyObject)childElement, callbackDelegate);
            }
        }
    }
}

关于wpf - 在带有 WPF 的 MVVM 中,如何对 ViewModel 和 View 之间的链接进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2288765/

相关文章:

c# - MVVM Light - 多个 ViewModel(并将它们连接起来)

WPF MVVM View 问题

wpf - 如何在根元素的所有子元素上监听 Binding.SourceUpdated?

java - 我如何在java中编写时间戳以便我可以插入mysql

database - 数据库插入调用应该返回什么?

c# - WPF:将变量从父 xaml 传递给用户控件

cocoa - 使用 OCMock stub 返回 BOOL 的方法

java - 应该如何设计执行 CRUD 操作的 Bean 的单元测试?

unit-testing - AssertJ:记录所有通过(和失败)的断言

http - Angular.JS 尝试使用 OPTIONS HTTP 方法加载 View 失败