3

是否可以在没有“复制本地”依赖项的情况下运行单元测试,在运行时加载程序集?

更多细节:

我的 .net 解决方案如下所示:

  • MainProject (exe) [取决于“Class1Project”并在运行时使用“AssemblyLoaderProject”加载它]。

    'Class1Project' 设置为 'copy local = false' 和 'AssemblyLoaderProject' 设置为 'copy local = true'

  • Class1Project (dll)

  • AssemblyLoaderProject(使用 AppDomain.CurrentDomain.AssemblyResolve 和 Assembly.LoadFrom 在运行时加载和解析依赖项程序集)

  • UnitTestsProject(Nunit 或 MSTest)

在单元测试项目中,我正在尝试测试“Class1Project”,并且希望将其配置设置为与 MainProject 相同。

这意味着,UnitTestProject 还使用“copy local = false”引用“Class1Project”,并使用“copy local = true”引用“AssemblyLoaderProject”,并使用它在运行时加载程序集。

但由于某种原因,单元测试无法执行,运行程序抛出 FileNotFoundException 指定它无法解析“Class1Project”程序集。

尝试调试它,我发现测试运行程序甚至没有找到告诉 AssemblyLoaderProject 加载程序集的代码。

测试代码如下所示:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        Loader.LoadAssemblies();
        Class1 cls = new Class1();
        Assert.IsTrue(true);
    }
}

这是我尝试在 MSTest 上使用 VS2012 测试运行程序对其进行调试时收到的错误消息:

Test Name:  TestMethod1
Test FullName:  UnitTestProject1.UnitTest1.TestMethod1
Test Source:    c:\Users\user\Documents\Visual Studio 2012\Projects\ClassLibrary1\UnitTestProject1\UnitTest1.cs : line 13
Test Outcome:   Failed
Test Duration:  0:00:00.1177608

Result Message: 
Test method UnitTestProject1.UnitTest1.TestMethod1 threw exception: 
System.IO.FileNotFoundException: Could not load file or assembly 'ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.=== Pre-bind state information ===
LOG: User = \user
LOG: DisplayName = ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
 (Fully-specified)
LOG: Appbase = file:///C:/Users/user/Documents/Visual Studio 2012/Projects/ClassLibrary1/UnitTestProject1/bin/Debug
LOG: Initial PrivatePath = NULL
Calling assembly : UnitTestProject1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO 11.0\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\TESTWINDOW\vstest.executionengine.x86.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\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:/Users/user/Documents/Visual Studio 2012/Projects/ClassLibrary1/UnitTestProject1/bin/Debug/ClassLibrary1.DLL.
LOG: Attempting download of new URL file:///C:/Users/user/Documents/Visual Studio 2012/Projects/ClassLibrary1/UnitTestProject1/bin/Debug/ClassLibrary1/ClassLibrary1.DLL.
LOG: Attempting download of new URL file:///C:/Users/user/Documents/Visual Studio 2012/Projects/ClassLibrary1/UnitTestProject1/bin/Debug/ClassLibrary1.EXE.
LOG: Attempting download of new URL file:///C:/Users/user/Documents/Visual Studio 2012/Projects/ClassLibrary1/UnitTestProject1/bin/Debug/ClassLibrary1/ClassLibrary1.EXE.
Result StackTrace:  at UnitTestProject1.UnitTest1.TestMethod1()
4

4 回答 4

3

假设Loader.LoadAssemblies是注册AssemblyResolve事件的方法,您会收到此异常,因为运行时无法ClassLibrary1.dll通过探测找到。重要的是要了解为什么探测会在这里发挥作用。调用探测是因为在您可以通过Loader.LoadAssemblies该方法加载任何程序集之前,必须进行 Jitted。为了正确地进行jit,运行时必须为编译时引用的类型加载程序集。由于您已将“本地复制”设置为 false,因此该文件ClassLibrary1.dll未复制且不在探测路径中。因此,您的FileNotFoundException.

首先,我会尝试Loader.LoadAssemblies进入一个标有TestInitialize属性的方法,以便在每次测试之前运行。但是,根据在测试执行之前复制文件的位置,这也可能不起作用。您可能必须在测试设置中启用部署并使用该DeploymentItem属性。

一个更大的问题是:如果您进行单元测试,为什么不能将依赖项的“复制本地”设置为 true,以便将它们与测试程序集一起复制?

根据具体的Loader.LoadAssemblies操作,您可能会遇到由于程序集被加载到多个或不同的加载上下文而导致的其他问题。这可能会导致问题InvalidCastException,例如错误提示您无法将类型“X”转换为类型“X”。但是,您可能是安全的,因为如果通过探测未找到程序集,则会调用 AppDomain.AssemblyResolve 将程序集加载到 Load 上下文中。

于 2013-01-08T05:26:46.460 回答
1

我同意应该有一种方法来配置解析目录,就像 Mstest 使用“.runsettings”文件一样。

关于问题:

一个更大的问题是:如果您进行单元测试,为什么不能将依赖项的“复制本地”设置为 true,以便将它们与测试程序集一起复制?

好吧,答案是可能会使用很多依赖项的依赖项。

很难遵循像第 3 方这样的所有被动依赖关系。

我的意思是 - 如果您测试的程序集依赖于程序集 A,那么 A 可能依赖于 B。copy local true 将仅复制 A,但会在运行时失败,因为 B 丢失。考虑像整个程序集嵌套在以下文件夹中的情况:

  • 应用根
    • 应用主机.exe
    • 商业逻辑(文件夹)
    • 接口(文件夹)
    • 用户界面(文件夹)
    • 基础设施(文件夹)
    • 第 3 方(文件夹)

并且 apphost 具有 App.config,它允许目录探测以使运行时解析所有嵌套目录。

mstest ".runsettings" 可以在单元测试期间配置类似的程序集探测。XUnit 无法做到这一点。

一种解决方法是开始引用您的测试的大量程序集,每个程序集在您发现它不能被重新处理之后 - 但您仅在运行测试时才发现它。

这是一个糟糕且令人沮丧的解决方案。

我投票赞成插入一个更改请求,即 XUnit 也将支持目录探测配置。

那将非常有帮助。

(这实际上阻碍了我们从 mstest 升级到所需的 XUnit)。

于 2020-08-02T19:55:00.960 回答
0

您必须使 DLL'Class1Project' 可用于加载程序,因此,如果您不想将项目设置为始终复制它,您可以使用DeploymenItem属性复制它以进行测试,以便加载可以找到它。

于 2013-01-08T01:05:44.570 回答
0

VS2012 测试运行器中有一个错误。在我的项目中,我将所有依赖项设置为复制 local = true 并且仍然有一些 dll 没有被复制到“Out”文件夹中,从而导致测试失败。如果我在 VS2010 下运行相同的测试,一切都会完美运行。

使用 DeploymentAttribute 确实有帮助,但它不应该是必需的。

于 2013-01-31T16:44:30.377 回答