单元测试时私有ConfigurationManager字段抛出空引用错误如何解决
错误原因
- 直接触发空引用的原因:业务类的
_connectionString字段采用内联初始化,在你实例化DatabaseReaderGateway时会直接调用ConfigurationManager.ConnectionStrings["Database"]读取连接字符串,此时测试项目的App.config未正确复制到测试运行目录,导致无法读取到名为Database的连接字符串节点,返回null后调用.ConnectionString触发空引用异常。 - 隐含的架构问题:业务类没有采用依赖注入模式,硬编码了
IDapperReaderWrapper的实例化逻辑和连接字符串读取逻辑,你在测试中构造的_mockDapperReaderWrapper没有被注入到业务类实例中,即使解决了连接字符串的报错,Mock逻辑也不会生效,测试无法正常通过。
解决方案
临时修复空引用问题
右键测试项目中的App.config文件,选择「属性」,将「复制到输出目录」的属性值修改为「始终复制」或「如果较新则复制」,确保测试运行时目录下存在正确的配置文件,ConfigurationManager可以读取到对应连接字符串。
推荐的单元测试友好改造方案
1. 改造业务类,改为依赖注入模式
移除业务类中硬编码的依赖初始化逻辑,通过构造函数传入外部依赖:
public class DatabaseReaderGateway { private readonly string _connectionString; private readonly IDapperReaderWrapper _dapperReaderWrapper; public DatabaseReaderGateway(string connectionString, IDapperReaderWrapper dapperReaderWrapper) { _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString)); _dapperReaderWrapper = dapperReaderWrapper ?? throw new ArgumentNullException(nameof(dapperReaderWrapper)); } /// <summary> /// Retrieves a list of admins from the database. /// </summary> /// <returns>List of admins.</returns> public List<Admin> RetrieveListOfAdmins() { var adminDatabaseReader = new AdminDatabaseReader(_connectionString, _dapperReaderWrapper); return adminDatabaseReader.GetAll(); } }
2. 修改测试初始化逻辑,注入Mock依赖
在测试初始化时将测试用连接字符串和Mock对象传入业务类构造函数:
[TestInitialize] public void Initialize() { _connectionString = DatabaseShared.GetTestingConfigurationFile(); _mockDapperReaderWrapper = new Mock<IDapperReaderWrapper>(); // 注入测试依赖 _databaseReaderGateway = new DatabaseReaderGateway(_connectionString, _mockDapperReaderWrapper.Object); }
3. 修复断言逻辑
原测试中使用Assert.AreEqual比较两个列表默认是比较引用地址,无法校验列表内容是否一致,改为集合校验:
// 替换原有的AreEqual断言 CollectionAssert.AreEqual(expectedListOfAdmins, actualListOfAdmins, "我们期望列表内容一致,但实际不一致。");
可选优化:简化连接字符串读取逻辑
直接按名称读取连接字符串,无需遍历:
public static string GetTestingConfigurationFile() { ExeConfigurationFileMap configFileMap = new() { ExeConfigFilename = "App.config" }; var config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None); return config.ConnectionStrings.ConnectionStrings["Database"].ConnectionString; }
内容的提问来源于stack exchange,提问作者James McKinney
相关产品推荐
相关产品推荐

