Tod*_*les 10 c# testing wpf xaml
我已经达到了这样的程度,我想编写一个自动化测试来验证WPF视图的内容,该视图与特定状态下的视图模型绑定.
在概念上,它相当简单.创建视图模型,设置其状态,创建适当的视图,将视图添加到窗口,设置视图的数据上下文,显示窗口,截取屏幕截图,与先前截取的屏幕截图进行比较.此类测试对于检测意外更改以及验证是否可以无误地创建所有View都非常有用.
但是,创建我的View实例证明是有问题的.它需要一组未包含在XAML定义中的资源.这些资源包含在实际应用程序中的应用程序级资源字典中,因此在实际应用程序中创建View时,这些资源已经可用.
当我在我的测试中创建此View的实例时,它会抛出一个关于无法找到各种资源的XamlParseException(可以理解).
我不想简单地将适当的资源字典添加到View本身的XAML定义中,因为这会增加创建其中一个View对象所需的工作量(计算机工作量),以及增加每个所需的内存量.实例.我的理解是,这是ResourceDictionary没有以这种方式共享的结果.
我试过了:
从本质上讲,我需要知道是否有办法设计一种情况,我可以为自动测试中使用的WPF组件的独立实例配置一组应用程序资源.
您可以通过创建以下结构来重现该问题,除了一个项目中的View_Test.cs文件之外的所有文件,以及生活在测试项目中的View_Test.cs文件.运行应用程序,它的工作原理.运行测试但失败.
App.xaml中
<Application
x:Class="Blah.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Run Code Online (Sandbox Code Playgroud)
Styles.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="SpecialBrush" Color="Black" />
</ResourceDictionary>
Run Code Online (Sandbox Code Playgroud)
MainWindow.xaml
<Window
x:Class="Blah.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Blah="clr-namespace:Blah"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Blah:View/>
</Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)
View.xaml
<UserControl
x:Class="AutomatedTestUserControlApplicationResources.View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Background="{StaticResource SpecialBrush}">
</Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新:
我有一些运气,为有问题的View创建一个额外的构造函数,它接受一个ResourceDictionary,作为一种方法,为View初始化注入一些上下文.此构造函数重载仅用于测试,在实际应用程序中,资源上下文已从Application资源中获得.
public View(ResourceDictionary resourceContext = null)
{
if (resourceContext != null) Resources.MergedDictionaries.Add(resourceContext);
InitializeComponent();
}
Run Code Online (Sandbox Code Playgroud)
这解决了我上面发布的一个特定的例子,它不依赖于初始化不相关的对象只是为了让View工作(面对良好的依赖注入实践).
但是,当我尝试在我的实际项目中实现它时,它揭示了一些其他问题.我在应用程序级别的资源上下文实际上是4个不同资源字典的合并,后者依赖于前面的(因为它们引用了先前条目中指定的资源).
AppResources.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Style/GlobalColour.xaml"/>
<ResourceDictionary Source="Style/GlobalBrush.xaml"/> <!-- Dependent on GlobalColour-->
<ResourceDictionary Source="Style/GlobalStyle.xaml"/>
<ResourceDictionary Source="Resources/GlobalContent.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Run Code Online (Sandbox Code Playgroud)
在我的测试项目中从这个文件创建一个ResourceDictionary,然后在构造期间将ResourceDictionary注入我的View会抛出一个与未找到的StaticResource相关的XamlParseException(无法找到的资源存在于GlobalBrush中,并且依赖于GlobalColour中的一个条目).
随着我的进一步探索,我会更新.
更新:
我完全没有运气手动创建和使用上面的AppResources ResourceDictionary.我无法使MergedDictionaries中的字典之间的相互依赖性起作用.我甚至无法手动压平ResourceDictionary实例,因为当我尝试访问依赖于并行字典中的资源的字典中的资源时,它抛出了XamlParseException.
因此,通过构造函数将ResourceDictionary注入View的想法在我的解决方案中使用是不可行的(尽管如果应用程序资源是一个平坦的ResourceDictioanry,它可以工作).
在这个旅程结束时,我得出的结论是,实例化一个视图,其中xaml不直接包含对资源的引用(无需实例化整个应用程序)的唯一方法是包含对适当的ResourceDictionary的引用,无论在哪里资源直接在xaml中使用.然后,您必须使用SharedResourceDictionary在运行时管理性能问题(因为您要实例化数百个重复的ResourceDictionaries)(互联网上有许多此概念的实现).
Dav*_*wen 12
实际上,您只需要使用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();
}
}
Run Code Online (Sandbox Code Playgroud)
我只是看了一些反汇编代码,看看它是如何在内部完成的,这可以简化为不需要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();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1836 次 |
| 最近记录: |