自动测试期间的WPF组件资源

  发布于 2023-02-07 20:51

我已经达到了这样的程度,我想编写一个自动化测试来验证WPF视图的内容,该视图与特定状态下的视图模型绑定.

在概念上,它相当简单.创建视图模型,设置其状态,创建适当的视图,将视图添加到窗口,设置视图的数据上下文,显示窗口,截取屏幕截图,与先前截取的屏幕截图进行比较.此类测试对于检测意外更改以及验证是否可以无误地创建所有View都非常有用.

但是,创建我的View实例证明是有问题的.它需要一组未包含在XAML定义中的资源.这些资源包含在实际应用程序中的应用程序级资源字典中,因此在实际应用程序中创建View时,这些资源已经可用.

当我在我的测试中创建此View的实例时,它会抛出一个关于无法找到各种资源的XamlParseException(可以理解).

我不想简单地将适当的资源字典添加到View本身的XAML定义中,因为这会增加创建其中一个View对象所需的工作量(计算机工作量),以及增加每个所需的内存量.实例.我的理解是,这是ResourceDictionary没有以这种方式共享的结果.

我试过了:

在测试中创建App.xaml的实例(设置Application.Current属性).

将Application.Current.Resources属性设置为App.xaml实例的Resources属性.

直接设置Page的Resources属性.

直接设置Window的Resources属性(为测试添加页面的Window).

从本质上讲,我需要知道是否有办法设计一种情况,我可以为自动测试中使用的WPF组件的独立实例配置一组应用程序资源.

您可以通过创建以下结构来重现该问题,除了一个项目中的View_Test.cs文件之外的所有文件,以及生活在测试项目中的View_Test.cs文件.运行应用程序,它的工作原理.运行测试但失败.

App.xaml中


    
        
            
                
            
        
    

Styles.xaml


    

MainWindow.xaml


    
        
    

View.xaml


    

    

View_Test.cs

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Blah;
using System.Windows;

namespace Blah.Test
{
    [TestClass]
    public class View_Test
    {
        [TestMethod]
        public void Test()
        {
            var view = new View();

            var window = new Window();
            window.Content = view;

            window.ShowDialog();
        }
    }
}

更新:

我有一些运气,为有问题的View创建一个额外的构造函数,它接受一个ResourceDictionary,作为一种方法,为View初始化注入一些上下文.此构造函数重载仅用于测试,在实际应用程序中,资源上下文已从Application资源中获得.

public View(ResourceDictionary resourceContext = null)
{
    if (resourceContext != null) Resources.MergedDictionaries.Add(resourceContext);
    InitializeComponent();
}

这解决了我上面发布的一个特定的例子,它不依赖于初始化不相关的对象只是为了让View工作(面对良好的依赖注入实践).

但是,当我尝试在我的实际项目中实现它时,它揭示了一些其他问题.我在应用程序级别的资源上下文实际上是4个不同资源字典的合并,后者依赖于前面的(因为它们引用了先前条目中指定的资源).

AppResources.xaml


    
        
         
        
        
    

在我的测试项目中从这个文件创建一个ResourceDictionary,然后在构造期间将ResourceDictionary注入我的View会抛出一个与未找到的StaticResource相关的XamlParseException(无法找到的资源存在于GlobalBrush中,并且依赖于GlobalColour中的一个条目).

随着我的进一步探索,我会更新.

更新:

我完全没有运气手动创建和使用上面的AppResources ResourceDictionary.我无法使MergedDictionaries中的字典之间的相互依赖性起作用.我甚至无法手动压平ResourceDictionary实例,因为当我尝试访问依赖于并行字典中的资源的字典中的资源时,它抛出了XamlParseException.

因此,通过构造函数将ResourceDictionary注入View的想法在我的解决方案中使用是不可行的(尽管如果应用程序资源是一个平坦的ResourceDictioanry,它可以工作).

在这个旅程结束时,我得出的结论是,实例化一个视图,其中xaml不直接包含对资源的引用(无需实例化整个应用程序)的唯一方法是包含对适当的ResourceDictionary的引用,无论在哪里资源直接在xaml中使用.然后,您必须使用SharedResourceDictionary在运行时管理性能问题(因为您要实例化数百个重复的ResourceDictionaries)(互联网上有许多此概念的实现).

1 个回答
  • 实际上,您只需要使用Application.LoadComponent来创建所有内容的实例,以便在正确的时间提供正确的资源.

    关键是通过其XAML加载所有内容而不是创建类的实例,因为类只包含一半的信息.

    [TestClass]
    public class View_Test
    {
        [TestMethod]
        public void Test()
        {
            //set initial ResourceAssembly so we can load the App
            Application.ResourceAssembly = Assembly.GetAssembly(typeof (App));
    
            //load app
            var app = (App) Application.LoadComponent(new Uri("App.xaml", UriKind.Relative));
    
            //load window and assign to app
            var mainWindow = (Window) Application.LoadComponent(new Uri("MainWindow.xaml", UriKind.Relative));
            app.MainWindow = mainWindow;
    
            //load view and assign to window content
            var view = (UserControl) Application.LoadComponent(new Uri("View.xaml", UriKind.Relative));
            mainWindow.Content = view;
    
            //show the window
            mainWindow.Show();
        }
    }
    

    编辑:更简单的版本

    我只是看了一些反汇编代码,看看它是如何在内部完成的,这可以简化为不需要XAML引用.让事情进行的最重要的部分是设置Application.ResourceAssembly和创建App并调用InitializeComponent它.窗口不是特别必要的,您可以创建一个新窗口来保存视图.

    [TestClass]
    public class View_Test
    {
        [TestMethod]
        public void Test()
        {
            Application.ResourceAssembly = Assembly.GetAssembly(typeof (App));
    
            var app = new App();
            app.InitializeComponent();
    
            var mainWindow = new MainWindow();
            app.MainWindow = mainWindow;
    
            var view = new View();
            mainWindow.Content = view;
            mainWindow.Show();
        }
    }
    

    2023-02-07 20:52 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有