我正在为WPF应用程序编写一些单元测试,尽管我试图避免使用它,但我还是有一些正在测试的代码实例化View。一旦实例化视图,就会评估所有标记扩展,样式等。为了解决这个问题,我在初始化测试程序集时创建了一个虚拟的 Application 并注册了所有必需的资源:
[TestClass]
public class AssemblyInitialize
{
[AssemblyInitialize]
public static void SetupTestAssembly(TestContext context)
{
if (Application.Current == null)
new Application();
var resources = new List<string>
{
"pack://application:,,,/AssemblyName;component/ResourceDictionary.xaml"
};
foreach(var resource in resources)
{
var uri = new Uri(resource);
var dictionary = new ResourceDictionary { Source = uri };
Application.Current.Resources.MergedDictionaries.Add(dictionary);
}
}
}
我过去曾使用过这种方法,而且运行正常。
我用这种方法遇到了一个小麻烦。我有一些资源在包Uri中使用 pack:// siteoforigin:,当测试实例化此视图时,我收到一条关于无法解析文件的错误。
XAML:
<ResourceDictionary
xmlns="...">
<ImageBrush
x:Key="ResourceName"
ImageSource="pack://siteoforigin:,,,/Resources/image.png"
/>
</ResourceDictionary>
错误消息:
Could not find a part of the path 'C:\\Solution\\TestResults\\Workspace_2012-03-01 14_54_29\\Resources\\image.png'
我已将Resources目录添加为部署项目,并且我已确认该图像是TestRun输出目录。似乎AppDomain在我的测试程序集的位置上方运行一个文件夹,因为该文件实际位于:
c:\ Solution \ TestResults \ Workspace_2012-03-01 14_54_29 \ Out \ Resources \ image.png
关于如何让WPF应用程序使用Out目录作为主文件夹的任何建议?
答案 0 :(得分:3)
这是因为您的测试运行器设置的AppDomain.BaseDirectory
没有尾随'/'
字符,这会导致解析siteoforigin
路径的代码丢失最后一个目录路径。
您可以通过在正常运行或测试中查看以下代码的结果来检查这一点。
Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory);
最近在NUnit中已经fixed(包含在2.6中),但可能仍然是其他测试跑步者的问题。
如果您感兴趣,这相当于siteoforigin
代码正在执行的操作:
new Uri(new Uri(baseDirectory), "some/relative/path.jpg").LocalPath
在baseDirectory
中使用和不使用尾部斜杠尝试。
答案 1 :(得分:1)
我已经成功解决了这个问题,如answer above所述,通过反射更改了AppDomain.CurrentDomain.BaseDirectory
:
private static void FixWpfPackSiteOfOriginReferences()
{
// note: xunit does not add a trailing slash to the BaseDirectory path.
// When you start the application, there's a trailing slash.
// Also see:
// - https://stackoverflow.com/a/9908449/684096
// - https://github.com/dotnet/runtime/issues/7866#issuecomment-299761968
var appDomainSetup = GetInstancePropertyValueViaReflection<AppDomainSetup>(
AppDomain.CurrentDomain,
"FusionStore");
if (!appDomainSetup.ApplicationBase.EndsWith(
Path.DirectorySeparatorChar.ToString()))
{
appDomainSetup.ApplicationBase += Path.DirectorySeparatorChar;
}
}
private static T GetInstancePropertyValueViaReflection<T>(
object instance,
string propertyName)
{
PropertyInfo property = GetInstancePropertyInfo(instance, propertyName);
return (T)property.GetValue(instance);
}
private static PropertyInfo GetInstancePropertyInfo(
object instance,
string propertyName)
{
Type instanceType = instance.GetType();
PropertyInfo propertyInfo = instanceType
.GetProperty(
propertyName,
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (propertyInfo == null)
{
throw new ArgumentOutOfRangeException(
nameof(propertyName),
propertyName,
FormattableString.Invariant(
$"{instanceType} does not have a property '{propertyName}'"));
}
return propertyInfo;
}
这是在测试中创建Wpf-App之前完成的,对于我来说,它本身是通过xunit collection fixture进行范围确定的。