4

我为 ReSharper 编写了 xunit.net 测试运行程序,并且在 8.0 版本中遇到了问题 - 我看到程序集无法加载到影子复制的 AppDomain 中。相同的代码和测试项目在 7.1 版本中运行良好。不过,我不明白为什么。

运行测试时,ReSharper 会生成一个可执行文件来加载我的插件。我使用 xunit.net 的 API 创建启用了卷影复制的 AppDomain。测试项目程序集被复制到卷影副本缓存中,并开始加载。它将依赖项复制到缓存中,并加载它 - FakeItEasy 的旧版本,它使用 Assembly.LoadFile 加载当前目录中的所有程序集,即测试项目的 bin\Debug 文件夹。因此,FakeItEasy 将这些程序集加载到既不加载上下文中。由于它使用 LoadFile,它绕过了卷影副本缓存,并且文件直接从 bin\Debug 文件夹加载。

之后,测试项目的依赖加载失败,导致 FileNotFoundException。Fusion 绑定日志显示它尝试加载它们,但它们没有被复制到卷影副本缓存中,并且它们无法加载。我不明白为什么。这是绑定失败:

LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using host configuration file: 
LOG: Using machine configuration file from     C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/temp/todonancy/TodoNancyTests/bin/Debug/Nancy.Testing.DLL.
LOG: Assembly download was successful. Attempting setup of file: C:\temp\todonancy\TodoNancyTests\bin\Debug\Nancy.Testing.dll
LOG: Entering download cache setup phase.
LOG: Assembly Name is: Nancy.Testing, Version=0.17.1.0, Culture=neutral, PublicKeyToken=null
ERR: Setup failed with hr = 0x80070003.
ERR: Failed to complete setup of assembly (hr = 0x80070003). Probing terminated.

如果我禁用卷影副本缓存,或者使用不使用 LoadFile 的较新版本的 FakeItEasy,则一切正常。但是,我不能责怪 FakeItEasy 的旧版本 - 我让用户在其他项目和程序集上看到相同的错误,所有这些都通过禁用卷影副本缓存来解决。

此外,此方案适用于 ReSharper 7.1 - 相同的插件代码和相同的测试项目。唯一的区别是主机应用程序,但我看不出它有什么不同——例如,没有订阅其他程序集解析事件处理程序。唯一真正的区别是 7.1 主机使用远程处理与 Visual Studio 应用程序对话,而 8.0 使用简单的 TCP 套接字。

有谁知道为什么这在 8.0 版本中失败,但在 7.1 中运行?

编辑(2013 年 7 月 8 日):

我设法通过一个简单的测试使其失败:

[Fact]
public void Thing()
{
  Assert.NotNull(Nancy.Bootstrapper.AppDomainAssemblyTypeScanner.Assemblies);
}

使用直接添加到项目中的 Nancy 类的副本(使用引用的ScanModeAssemblyExtensions类)。项目中唯一的其他内容是对 xunit.dll 和 xunit.extensions.dll 的引用。

它不会每次都失败,它令人沮丧地断断续续,但我可以让它FileNotFoundException这个调用中Assembly.ReflectionOnlyLoadFrom抛出一个,同时尝试从 bin\Debug 文件夹加载测试程序集。

这是来自异常的融合日志:

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
Running under executable  C:\Program Files (x86)\JetBrains\ReSharper\v8.0\Bin\JetBrains.ReSharper.TaskRunner.CLR4.MSIL.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: Where-ref bind. Location = C:\Users\Matt\Code\scratch\WeirdXunitFailures\WeirdXunitFailures\bin\Debug\WeirdXunitFailures.dll
LOG: Appbase = file:///C:/Users/Matt/Code/scratch/WeirdXunitFailures/WeirdXunitFailures/bin/Debug
LOG: Initial PrivatePath = NULL
Calling assembly : (Unknown).
===
LOG: This is an inspection only bind.
LOG: No application configuration file found.
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Attempting download of new URL file:///C:/Users/Matt/Code/scratch/WeirdXunitFailures/WeirdXunitFailures/bin/Debug/WeirdXunitFailures.dll.
ERR: Failed to complete setup of assembly (hr = 0x80070003). Probing terminated.

不幸的是,这并没有告诉我——file:// url 是有效的,并且卷影副本缓存包含 xunit.dll 和 WeirdXunitFailures.DLL(测试项目)。此外,调试器中的“模块”窗口显示 WeitdXunitFailures.dll 已从卷影副本缓存位置加载。

再一次,真正奇怪的是 7.1 跑步者工作得很好。

编辑:

事实上,我可以通过调用它来让它失败:

[Fact]
public void Thing()
{
  Assembly.ReflectionOnlyLoadFrom(@"C:\Users\Matt\Code\scratch\WeirdXunitFailures\WeirdXunitFailures\bin\Debug\xunit.dll");
  Assembly.ReflectionOnlyLoadFrom(@"C:\Users\Matt\Code\scratch\WeirdXunitFailures\WeirdXunitFailures\bin\Debug\xunit.extensions.dll");
  Assembly.ReflectionOnlyLoadFrom(@"C:\Users\Matt\Code\scratch\WeirdXunitFailures\WeirdXunitFailures\bin\Debug\WeirdXunitFailures.dll");
}

这些是项目 dll 和两个 xunit dll。它仍然很断断续续,但似乎在完全重建后最容易重现,尽管在几次成功运行后仍然会发生(所以不是重建有问题)

4

1 回答 1

2

呸。问题(自然)是 ReSharper 8 中行为的细微变化。

测试运行程序进程 API 有一种方法可以告诉 ReSharper 主进程(即 devenv.exe)用于测试运行的临时文件夹的位置 - 卷影副本缓存。这是因为测试运行程序进程通常无法删除缓存文件夹,因为它仍在使用中。然后,ReSharper 将多次尝试为您删除该文件夹,让该过程有时间优雅地结束。

ReSharper 7.1 将在测试运行结束时删除此文件夹,或者如果运行被中止。

只要您调用该方法,ReSharper 8 就会删除该文件夹。nunit 测试运行程序在测试运行结束时告诉 ReSharper 。我一开始就告诉它。因此,当我的测试正在运行时,ReSharper 会很高兴地出现,并从卷影副本缓存中删除它可以删除的任何内容,使其看起来像卷影副本缓存已正确损坏。

我想我会提交一个错误:)

于 2013-08-07T16:50:58.153 回答