You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mock Dynamic QueryAsync触发Dapper空引用异常,求排查方案

数据库连接单元测试Mock Dapper时出现空引用异常问题

我在编写数据库连接的单元测试Mock代码时遇到了空引用异常,以下是我的Mock代码:

var connection = new Mock<IDatabaseConnectionFactory>();
var conn = new Mock<IDbConnection>();

connection.Setup(c => c.GetConnection()).Returns(conn.Object);

_productRepository = new ProductRepository(connection.Object, _httpContextAccessorMock.Object);

var listDyn = new List<dynamic>();
listDyn.Add(1);
conn.SetupDapperAsync(c => c.QueryAsync(It.IsAny<string>(), It.IsAny<object>(),
        It.IsAny<IDbTransaction>(), It.IsAny<int>(), It.IsAny<CommandType>()))
    .ReturnsAsync(listDyn.AsEnumerable());

var model = new Model()
{ name = "test", owner = "owner "};
var result = _productRepository.AddProduct(model);

调用AddProduct(model)时,在这段Dapper调用代码处触发错误:

await connection.QueryAsync("[dbo].[storedProcName]",
              param: parameters, commandType: CommandType.StoredProcedure).ConfigureAwait(false)

错误信息:

Message: "Object reference not set to an instance of an object."
Source: "Dapper"

堆栈跟踪:

Object reference not set to an instance of an object. at Dapper.DynamicParameters.AddParameters(IDbCommand command, Identity identity)
at Dapper.DynamicParameters.Dapper.SqlMapper.IDynamicParameters.AddParameters(IDbCommand command, Identity identity)
at Dapper.SqlMapper.<>c__DisplayClass165_0.b__0(IDbCommand cmd, Object obj)
at Dapper.CommandDefinition.SetupCommand(IDbConnection cnn, Action2 paramReader) at Dapper.SqlMapper.<QueryAsync>d__331.MoveNext()
at Repository.Repositories.VendorRepository.d__13.MoveNext() in C:\Users\xxxxx\Documents\xxx\Projects\xxxApi\Infrastructure\Repository\Repositories\ProductRepository.cs:line 168

请问我是不是遗漏了什么配置?


问题原因

空引用异常来自Dapper的DynamicParameters.AddParameters方法,说明Mock过程中Dapper需要操作的IDbCommand对象未正确初始化——你只Mock了QueryAsync方法,但Dapper执行查询时会创建IDbCommand并尝试添加参数,而Mock的IDbConnection没有配置CreateCommand方法,导致返回的IDbCommand为null,进而触发空引用。

解决步骤

  1. Mock IDbCommand及必要成员
    需要创建IDbCommand的Mock实例,至少配置CreateParameter方法(Dapper添加参数时会用到),同时确保IDbConnection的CreateCommand返回这个Mock的Command对象。

  2. 更新后的Mock代码

    var connection = new Mock<IDatabaseConnectionFactory>();
    var conn = new Mock<IDbConnection>();
    // 新增IDbCommand的Mock实例
    var cmdMock = new Mock<IDbCommand>();
    // 新增IDbDataParameter的Mock实例(Dapper添加参数依赖此对象)
    var paramMock = new Mock<IDbDataParameter>();
    
    // 配置Connection的CreateCommand返回Mock的Command
    conn.Setup(c => c.CreateCommand()).Returns(cmdMock.Object);
    // 配置Command的CreateParameter返回Mock的参数
    cmdMock.Setup(c => c.CreateParameter()).Returns(paramMock.Object);
    
    connection.Setup(c => c.GetConnection()).Returns(conn.Object);
    
    _productRepository = new ProductRepository(connection.Object, _httpContextAccessorMock.Object);
    
    var listDyn = new List<dynamic>();
    listDyn.Add(1);
    conn.SetupDapperAsync(c => c.QueryAsync(It.IsAny<string>(), It.IsAny<object>(),
            It.IsAny<IDbTransaction>(), It.IsAny<int>(), It.IsAny<CommandType>()))
        .ReturnsAsync(listDyn.AsEnumerable());
    
    var model = new Model()
    { name = "test", owner = "owner "};
    // 注意:AddProduct是异步方法,必须用await等待执行完成
    var result = await _productRepository.AddProduct(model);
    
  3. 额外注意事项

    • 原代码中调用AddProduct时未使用await,如果该方法是异步的,会导致任务未完成就继续执行,可能引发其他问题,务必加上await。
    • 如果你的存储过程需要处理特定参数逻辑,可能需要进一步MockIDbCommand的Parameters集合,但基础场景下以上配置已能解决空引用问题。

内容的提问来源于stack exchange,提问作者choopau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 18:15:07