Visual Studio 2015 中使用 Fakes 进行单元测试时出现 InvalidProgramException

27

我正在使用Visual Studio 2015 Enterprise RTM编写单元测试,针对一个使用Unity容器的项目。

我发现即使不实际使用伪造程序集,只是添加 Unity 的伪装程序集就足以生成以下异常:

System.InvalidProgramException:公共语言运行时检测到无效程序。



请按照以下步骤重现此问题:

  • 使用 Visual Studio 2015 Enterprise RTM 创建 .NET 4.6 单元测试项目

  • 添加 NuGet 包“Unity”版本3.5.1404.0

  • 添加 NuGet 包“CommonServiceLocator”版本1.2.0

  • 编写一个单元测试,如下所示:

[TestClass]
public class UnitTest1 : IDisposable
{
    [TestMethod]
    public void TestMethod1()
    {
        new ResolvedArrayParameter<IDisposable>(new IDisposable[] {this});
    }

    void IDisposable.Dispose()
    {
    }
}
  • 验证测试是否通过

  • 右键单击 Microsoft.Practices.Unity 引用,选择“添加伪装程序集”

  • 重新运行测试

  • 观察以下异常测试失败:

测试名称: TestMethod1
测试全名: UnitTestProject11.UnitTest1.TestMethod1
测试源: c:\temp\UnitTestProject11\UnitTestProject11\UnitTest1.cs : line 12
测试结果: 失败
测试持续时间: 0:00:00.0572447

结果堆栈跟踪:

at Microsoft.Practices.Unity.ResolvedArrayParameter..ctor(Type arrayParameterType, Type elementType, Object[] elementValues)
at Microsoft.Practices.Unity.ResolvedArrayParameter`1..ctor(Object[] elementValues)
at UnitTestProject11.UnitTest1.TestMethod1() in c:\temp\UnitTestProject11\UnitTestProject11\UnitTest1.cs:line 13
结果消息:
测试方法 UnitTestProject11.UnitTest1.TestMethod1 引发异常:
System.InvalidProgramException: Common Language Runtime detected an invalid program.



这个问题最不寻常的特点显然是即使在代码中没有直接出现伪装,故障仍会出现。

进行了大量试验后发现,将测试项目重新定位到 .NET 4.5 就可以“解决”问题,但这对我来说是不可行的,因为我之前发布了一个其他问题。

即使使用几乎所有伪装设置(代码合同等)也没有找到解决方案。

非常感谢您在此问题上提供的任何建议。


开始了一项悬赏,因为我们在使用“ShimLocalPrintServer.Constructor…”测试实例化“System.Printing.LocalPrintServer”方法时遇到了相同的“InvalidProgramException”。不需要“UnityContainer”即可重现该错误。重置框架也没有帮助。当被测试的方法调用“new LocalPrintServer(new string[0], PrintSystemDesiredAccess.EnumerateServer);”时会引发异常。 - René Vogt
你为什么还没有安装Visual Studio更新1呢? - CSharpie
1
其中的程序集是否有 strong name 签名或已经签名? - Ben
1
我们曾广泛使用过Microsoft Fakes,但它给我们带来了无尽的痛苦。我们经常遇到很多奇怪和深奥的错误信息,就像这个一样。最终,我们放弃了Microsoft Fakes,并且再也没有回头看过它。 - bitbonk
查看您项目的构建属性,看看是否选中了“优化代码”选项...如果是,请取消选择并查看是否有效。 - Elmer Dantas
显示剩余2条评论
1个回答

2
唯一的通用解决方案是确保所有部件与您使用的CLR版本非常匹配,并且VS具有最新的更新。这个问题没有什么捷径。在注入Fakes时,您需要了解(挖掘)项目中连接的所有部件的确切CLR版本兼容性。请注意,“兼容性”可能只是清单的问题,但更频繁地涉及到最终代码生成的微妙差异以及虚拟机的哪个版本。这些事情通常对于运行和调试不重要,因为有几层可以确保次要版本差异无关紧要或者您会获得静默开关,以符合您的代码声明兼容性。但是,当您使用Fakes时,“系统”会将原始代码注入您的代码(包括涉及到的第三方库),这意味着它会跳过大多数检查-否则无法工作。但是,当实际运行代码时,引擎(虚拟机)必须进行一些检查以确保其自身的安全/完整性,如果看起来声明不足够匹配,它倾向于变得偏执并退出。这就是为什么有人问涉及的程序集是否强命名或签名的原因。这是“系统”真正信任的唯一保证级别。没有这个级别的保证,它将进行一定程度的猜测,虽然对于正常运行大多数情况下都没有关系,但对于代码注入来说非常重要。我仍然没有谈到可能出现的真正问题-这一切都假设实际代码很好,只是声明混淆了。您可以尝试玩弄它,但这需要很多时间和精力。更容易的方法是检查是否可以获得更好匹配的程序集版本。当您将您的版本切换回4.5时,错误消失的事实告诉您,或者涉及的某些程序集与4.6不够“接近”,或者可能存在某些代码注入故障,而这些故障已经通过您还没有采取的更新进行了修复。是的,这需要付出很多痛苦,但这就是想要处在前沿的代价。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接