【问题标题】:NSubstitute.Substitute.For<T>() throws a FileNotFound exception but only using MSTest on Visual StudioNSubstitute.Substitute.For<T>() 引发 FileNotFound 异常,但仅在 Visual Studio 上使用 MSTest
【发布时间】:2018-08-28 14:54:40
【问题描述】:

我们在使用 NSubstitute 时遇到问题,它无法找到某些 DLL。似乎问题发生在来自预编译 DLL 的模拟类型引用来自其他预编译 DLL 的类型时。所以我们有类似 A.dll 引用 B.dll 中的类型的东西,它也引用了 C.dll 中的类型。有一个异常告诉我们找不到 C.dll,即使它在 bin 文件夹中并且在项目中正确引用。所有版本也匹配。通过删除对 C dll 的引用,我设法通过了一些测试。我还检查了预编译的解决方案,并且 DLL 版本是一致的。所有 Nuggets 在项目中也是最新的。所有构建架构、发布和语言版本也是一致的。

让这个问题更奇怪的是,在我们的持续集成服务器中使用 VSTest.Console 不会重现问题,而且我没有看到运行的测试数量减少,它只是使用 VS 测试资源管理器。 ReSharper 的测试资源管理器也没有这个问题。我们在升级到 MSTest v2 时看到了这个问题,以前的版本可以正常工作。

这是堆栈跟踪(我截断了路径和命名空间):

Result StackTrace:  
at System.Reflection.Emit.TypeBuilder.TermCreateClass(RuntimeModule module, Int32 tk, ObjectHandleOnStack type)
   at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
   at System.Reflection.Emit.TypeBuilder.CreateTypeInfo()
   at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.CreateType(TypeBuilder type)
   at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()
   at Castle.DynamicProxy.Generators.InterfaceProxyWithoutTargetGenerator.GenerateType(String typeName, Type proxyTargetType, Type[] interfaces, INamingScope namingScope)
   at Castle.DynamicProxy.Generators.InterfaceProxyWithTargetGenerator.<>c__DisplayClass6_0.<GenerateCode>b__0(String n, INamingScope s)
   at Castle.DynamicProxy.Generators.BaseProxyGenerator.ObtainProxyType(CacheKey cacheKey, Func`3 factory)
   at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, IInterceptor[] interceptors)
   at NSubstitute.Proxies.CastleDynamicProxy.CastleDynamicProxyFactory.GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[] additionalInterfaces, Object[] constructorArguments)
   at NSubstitute.Core.SubstituteFactory.Create(Type[] typesToProxy, Object[] constructorArguments, SubstituteConfig config)
   at NSubstitute.Substitute.For[T](Object[] constructorArguments)
   at OurTests.Fixtures.MockBuilder.Build() in C:\MockBuilder.cs:line 10
   at UnitTests.TestInitialize()

TestCleanup Stack Trace
   at Tests.TestCleanup() in 
Result Message: 
Initialization method Tests.TestInitialize threw exception. System.IO.FileNotFoundException: Could not load file or assembly 'AssemblyC, Version=1, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified..

TestCleanup method Tests.TestCleanup threw exception. System.NullReferenceException: System.NullReferenceException: Object reference not set to an instance of an object..

请注意,我们在升级到 MSTest V2 时遇到问题,它会运行我们的 DLL 的调试版本而不是指定的发布版本,即使路径是绝对的。不知道有没有关系。

【问题讨论】:

  • 这个问题与您遇到的问题相同:social.msdn.microsoft.com/Forums/en-US/…
  • 我遇到了类似的问题,我通过不使用 MSTest 而是使用 NUnit 来“修复”它。我的根本原因是我正在模拟的对象引用了比单元测试项目更旧版本的 nuget 包,并且没有绑定重定向,因为有问题的 DLL 没有公钥令牌(不确定绑定重定向是否会实际上已经解决了这个问题)

标签: c# mstest nsubstitute


【解决方案1】:

经过两天的心理健康预算削减,我终于找到了解决办法。或者更确切地说是一个补丁,因为我仍然不能 100% 确定原因。

[ClassInitialize]
public static void ClassInitialize(TestContext testContext)
{
    AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolveEventHandler;
}

private static Assembly AssemblyResolveEventHandler(object sender, ResolveEventArgs args)
{
    var dllName = args.Name.Split(',')[0] + ".dll";
    var assemblyPath = Path.Combine(BinDir, dllName);
    return Assembly.LoadFile(assemblyPath);
}

请注意,这可能应该在 AssemblyInitialize 方法中。

我最好的猜测是,在 TestInitialize 方法中,它不会显式调用 DLL,因此此时它们不会被加载,而且 Castle(NSubstitute 使用的)显然还不知道它们,可能会尝试从当前已知的程序集中加载。但是当我们从持续集成脚本运行测试时,之前已经运行了其他测试,因此 DLL 已经可用(可能是全局程序集缓存?)。至于为什么 ReSharper 的 test runner 会起作用,我不知道,我猜他们在他们的产品中放了很多开发者糖果。

此外,信用到期:https://stackoverflow.com/a/8967026/4602726

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多