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

如何在EF Core中对使用FromSqlInterpolated的存储过程方法进行单元测试?

如何Mock存储过程调用的单元测试

你的当前Mock思路不生效,因为待测试方法并没有调用DbContext上的GetDataFromStoredProcedure方法,而是直接通过MyModel.FromSqlInterpolated执行SQL语句,所以需要针对DbSet<MyModel>的行为进行Mock,以下是两种可行方案:

方案一:Mock DbSet的FromSqlInterpolated行为

这种方式属于纯单元测试,完全隔离数据库依赖:

  1. 确保DbContext暴露DbSet属性
    首先在MyDBContext中添加对应实体的DbSet:

    public DbSet<MyModel> MyModels { get; set; }
    
  2. 调整待测试方法
    修改方法,从DbContext的DbSet调用FromSqlInterpolated:

    public async Task<List<MyModel>> GetDataFromStoredProcedure(int Id, CancellationToken cancellationToken)
    {
        return await _dbContext.MyModels.FromSqlInterpolated($"EXEC {MyStoredProcedure} {Id}").ToListAsync(cancellationToken);
    }
    
  3. 编写单元测试代码
    构建Mock DbSet并模拟FromSqlInterpolated的返回:

    // Arrange
    var mockData = await GetData();
    var mockDbSet = new Mock<DbSet<MyModel>>();
    
    // 将模拟数据转为IQueryable,模拟DbSet的查询能力
    var queryableData = mockData.AsQueryable();
    mockDbSet.As<IQueryable<MyModel>>().Setup(m => m.Provider).Returns(queryableData.Provider);
    mockDbSet.As<IQueryable<MyModel>>().Setup(m => m.Expression).Returns(queryableData.Expression);
    mockDbSet.As<IQueryable<MyModel>>().Setup(m => m.ElementType).Returns(queryableData.ElementType);
    mockDbSet.As<IQueryable<MyModel>>().Setup(m => m.GetEnumerator()).Returns(queryableData.GetEnumerator());
    
    // Mock FromSqlInterpolated方法,返回我们的Mock DbSet
    mockDbSet.Setup(m => m.FromSqlInterpolated(It.IsAny<FormattableString>()))
             .Returns(mockDbSet.Object);
    
    // 将Mock DbSet注入到DbContext
    var mockDBContext = new Mock<MyDBContext>(options);
    mockDBContext.Setup(x => x.MyModels).Returns(mockDbSet.Object);
    
    // 实例化待测试服务
    var service = new YourService(mockDBContext.Object);
    
    // Act
    var result = await service.GetDataFromStoredProcedure(1, CancellationToken.None);
    
    // Assert
    Assert.Equal(mockData.Count, result.Count);
    // 根据需求添加其他断言逻辑
    

方案二:使用内存数据库+拦截器模拟存储过程

这种方式更接近实际运行环境,适合轻量集成测试:

  1. 创建SQL命令拦截器
    拦截存储过程调用,返回模拟数据:

    public class StoredProcedureInterceptor : DbCommandInterceptor
    {
        private readonly List<MyModel> _mockData;
    
        public StoredProcedureInterceptor(List<MyModel> mockData)
        {
            _mockData = mockData;
        }
    
        public override InterceptionResult<DbDataReader> ReaderExecuting(
            DbCommand command,
            CommandEventData eventData,
            InterceptionResult<DbDataReader> result)
        {
            // 判断是否是目标存储过程调用
            if (command.CommandText.StartsWith($"EXEC {MyStoredProcedure}"))
            {
                // 构建模拟DataReader返回数据
                var dataTable = new DataTable();
                // 这里根据MyModel的属性添加对应列,示例假设Id和Name属性
                dataTable.Columns.Add("Id", typeof(int));
                dataTable.Columns.Add("Name", typeof(string));
                
                foreach (var item in _mockData)
                {
                    dataTable.Rows.Add(item.Id, item.Name);
                }
    
                var reader = dataTable.CreateDataReader();
                return InterceptionResult<DbDataReader>.SuppressWithResult(reader);
            }
    
            return base.ReaderExecuting(command, eventData, result);
        }
    }
    
  2. 编写测试代码
    配置内存数据库并注入拦截器:

    // Arrange
    var mockData = await GetData();
    var options = new DbContextOptionsBuilder<MyDBContext>()
        .UseInMemoryDatabase(databaseName: "TestDB")
        .AddInterceptors(new StoredProcedureInterceptor(mockData))
        .Options;
    
    using var dbContext = new MyDBContext(options);
    var service = new YourService(dbContext);
    
    // Act
    var result = await service.GetDataFromStoredProcedure(1, CancellationToken.None);
    
    // Assert
    Assert.Equal(mockData.Count, result.Count);
    // 添加其他断言逻辑
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 04:14:56