如何通过xUnit的testserver.dll.config传递DLL的app.config配置?
你的问题核心是xUnit测试环境下,my.dll无法读取自身配置,但依赖的logger.dll却可以,原因主要和配置文件加载机制以及xUnit的测试运行上下文有关,具体拆解如下:
可能的原因
配置文件绑定错误
my.dll在非测试环境下依赖my.dll.config,但xUnit的测试进程是testhost.exe,它默认加载的是testhost.dll.config,而非my.dll的独立配置文件。如果你的assemblySettings配置节没有被复制到testhost.dll.config里,或者自定义配置节的声明缺失,my.dll自然读不到配置,返回null。影子复制导致的路径问题
xUnit默认启用影子复制(Shadow Copy),会把测试依赖的dll复制到临时缓存目录再执行。如果my.dll是通过Assembly.GetExecutingAssembly().Location来定位自身的.config文件,这个路径指向的是缓存目录,而非原始目录,自然找不到对应的配置文件。配置读取逻辑的Assembly选择问题
虽然你说Assembly.GetCallingAssembly()能正确获取MyDll,但如果my.dll读取配置时用的是Assembly.GetExecutingAssembly()(比如在静态构造函数里),在xUnit的隔离执行环境下,这个调用可能返回的是testhost相关的程序集,而非my.dll,导致配置加载失败。
具体解决方法
方法1:合并配置到testhost.dll.config
把my.dll.config里的所有配置内容(包括自定义配置节的声明)完整复制到testhost.dll.config中。比如:
<configuration> <configSections> <!-- 必须包含自定义节的声明 --> <section name="assemblySettings" type="MyDll.AssemblySettingsSection, MyDll" /> </configSections> <!-- my.dll的配置项 --> <assemblySettings Hostname="test-local" Port="8080" /> <!-- logger.dll的配置保留 --> <appSettings> <add key="LogPath" value="C:\test-logs" /> </appSettings> </configuration>
这种方法最简单,适合测试环境快速验证。
方法2:修正配置读取逻辑
修改my.dll中读取配置的代码,用CodeBase替代Location获取原始程序集路径,避免影子复制的影响:
// 获取my.dll的原始文件路径(不受影子复制影响) var assembly = Assembly.GetCallingAssembly(); var assemblyPath = new Uri(assembly.CodeBase).LocalPath; // 拼接对应的.config文件路径 var configPath = $"{assemblyPath}.config"; // 加载指定的配置文件 var config = ConfigurationManager.OpenExeConfiguration(configPath); // 获取自定义配置节 var assemblySettings = (AssemblySettingsSection)config.GetSection("assemblySettings");
这种方法不需要修改测试项目的配置,更适合长期维护。
方法3:禁用xUnit影子复制
在测试项目中添加xunit.runner.json文件,禁用影子复制:
{ "shadowCopy": false }
注意要设置该文件的“复制到输出目录”属性为“如果较新则复制”。禁用后,Assembly.Location会指向原始dll目录,my.dll就能正常读取自身的.config文件。
为什么logger.dll的配置能生效?
大概率是logger.dll的配置读取逻辑依赖AppSettings这类全局配置节,而你已经把LogPath配置项添加到了testhost.dll.config里;或者logger.dll本身的配置加载逻辑更健壮,比如自动合并了依赖dll的配置,所以能正常读取。
内容的提问来源于stack exchange,提问作者j00hi

