5

我有一些我正在为 WPF 应用程序编写的单元测试,尽管我试图避免它,但我有一些正在测试的代码实例化了一个视图。一旦实例化视图,就会评估所有标记扩展、样式等。为了解决这个问题,我创建了一个虚拟应用程序并在初始化测试程序集时注册了所有必需的资源:

[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);
       }
    }
}

我过去使用过这种方法,它工作正常。

我用这种方法遇到了一个小障碍。我有一些使用pack://siteoforigin:在 pack Uri 中的资源,当测试实例化此视图时,我收到有关无法解析文件的错误。

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 目录作为其主文件夹的任何建议?

4

2 回答 2

4

这是因为AppDomain.BaseDirectory由您的测试运行程序设置的 没有尾随'/'字符,这会导致解析siteoforigin路径的代码丢失路径中的最后一个目录。

您可以通过在正常运行或测试时查看以下代码的结果来检查这一点。

Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory);

这最近已在 NUnit(包含在 2.6 中)中修复,但可能仍然是其他测试运行程序的问题。

如果您有兴趣,这相当于siteoforigin代码正在执行的操作:

new Uri(new Uri(baseDirectory), "some/relative/path.jpg").LocalPath

尝试使用和不使用baseDirectory.

于 2012-03-28T13:23:17.353 回答
1

正如上面的答案中所解释的,我通过更改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作用域的。

于 2020-08-20T06:16:00.807 回答