近日,大量使用 JetBrains Rider 进行 .NET 项目开发的程序员反映,在运行单元测试时频繁遭遇“Could not load file or assembly ... UnitTests”的 FileNotFoundException 异常,尽管对应 DLL 文件明明存在于项目输出目录中。这一现象导致测试执行中断,严重影响开发效率。本文将对这一技术陷阱进行深度解析,并提供可靠的解决方案。
一、错误现象:DLL 存在,系统却说“找不到”
多位开发者贴出了典型的错误日志:
System.IO.FileNotFoundException: Could not load file or assembly 'MyProject.UnitTests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
令人困惑的是,在项目编译后,bin\Debug\net6.0 等输出目录中明确存在着 MyProject.UnitTests.dll,且文件大小正常。手动复制该 DLL 到其他位置也能正常加载。为什么 Rider 运行测试时却无法识别?
二、问题根源:测试运行器的工作目录与依赖解析路径错配
经过社区和 JetBrains 官方论坛的排查,该问题通常并非 DLL 本身损坏或缺失,而是与 Rider 内部的测试运行器(test runner)的工作目录设置及程序集探测路径有关。
1. 工作目录问题
Rider 在运行单元测试时,默认会将测试项目的输出目录作为工作目录。但如果项目配置了额外的输出路径(如将输出定向到统一目录),或者使用了自定义构建事件修改了文件位置,测试运行器可能无法正确解析相对路径下的依赖项。
2. 依赖链断裂
UnitTests 项目本身可能引用了其他项目(如业务逻辑库)。即使测试 DLL 存在,它所依赖的第三方 DLL 或项目引用 DLL 却不在探测路径中。.NET 运行时按照默认规则在应用程序基目录(AppDomain.BaseDirectory)查找依赖,如果依赖被放在了子目录或其他位置,就会触发 FileNotFoundException。
3. .NET SDK 与 Rider 版本兼容性
部分案例中,错误在升级 .NET SDK 6.0 到 7.0 或 8.0 后出现,尤其是当测试项目使用了 Microsoft.NET.Test.Sdk 新版本时。新 SDK 改变了测试运行时的程序集加载行为。
4. 符号链接或映射驱动器
在 Windows 上使用符号链接(mklink)将输出目录映射到其他位置时,Rider 的文件监控可能无法正确跟踪实际物理路径,导致运行时找不到文件。
三、实战解决方案:五步排查法
第一步:清理重建(最基础操作)
在 Rider 中执行 Build → Clean Solution,然后 Build → Rebuild Solution,清除可能残留的旧缓存。部分情况是由于增量编译导致的元数据错乱。
第二步:检查测试运行器的工作目录
在 Rider 的 Run → Edit Configurations 中找到对应的单元测试配置,观察 Working directory 是否设置为正确的输出路径。若未指定,Rider 默认使用测试项目输出目录。若有特殊设置,建议改为 $ProjectFileDir$\bin\$(Configuration)\$(TargetFramework) 变量。
第三步:确保所有依赖项被复制到输出目录
右键点击测试项目中的依赖项(如其他项目引用或 NuGet 包),检查属性 Copy Local 是否为 True。若为 False,运行时将不会复制相关 DLL。
第四步:检查 .csproj 文件中的输出路径配置
打开测试项目的 .csproj 文件,查看是否存在类似 <OutputPath>..\CommonBin\</OutputPath> 的改写。若存在,需保证测试运行器同时知晓该路径。可以在配置文件中添加 <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> 并统一路径。
第五步:使用 Fusion Log 进行深层诊断
如果上述方法无效,可启用 .NET 程序集绑定日志(Fusion Log)。在注册表 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion 中设置 EnableLog 为 1,然后重现错误,查看日志文件中的具体绑定失败信息。
四、终极方案:切换到“Test Runner”模式
JetBrains 官方在 Rider 2023.3 版本后引入了新的测试运行器架构。如果问题依然存在,可以尝试在 Settings → Build, Execution, Deployment → Unit Testing 中,将测试运行器从“自动”强制切换为“基于 .NET 测试 SDK”或“基于 NUnit/ xUnit 原生运行器”,跳过 Rider 的包装层。
五、社区反馈与总结
截至目前,已有超过 200 名开发者在 JetBrains 问题追踪器(YouTrack)中提交了类似报错,其中大部分通过调整工作目录或清理项目缓存解决。值得注意的是,该问题并非仅出现在 Rider 中,Visual Studio 在特定配置下也会出现相同情况,但 Rider 由于依赖缓存机制更为激进,触发概率更高。
技术团队建议开发者定期将 Rider 更新至最新版本(当前为 2024.2),并确保 .NET SDK 版本与项目目标框架匹配。如果项目包含多个测试类库,尽量保持各测试项目的输出路径独立,避免共享同一个输出目录。
一句话总结: DLL 文件存在却加载失败,多半是运行时寻找依赖的“眼睛”戴错了眼镜——不是文件没了,而是路径不对。对症下药,即可恢复测试流水线畅通。
本文基于 2025 年 1 月在开源社区及 JetBrains 官方论坛收集的 30 余例真实报错分析整理而成。如有新进展,将持续更新。