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

.NET中Mock仓储ToListAsync()失败,提示不支持扩展方法

问题解决:Mock仓储GetQueryable().ToListAsync()时的NotSupportedException错误

错误根源

Moq无法Mock静态扩展方法(比如EntityFrameworkQueryableExtensions.ToListAsync),你直接在Setup中链式调用GetQueryable().ToListAsync的写法,Moq无法识别这种表达式,因此抛出错误。

解决步骤

1. 删除错误的Setup语句

直接删掉这行无效且触发错误的代码:

_mockRepo.Setup(x => x.GetQueryable<UserCompany>().ToListAsync(It.IsAny<CancellationToken>())).ReturnsAsync(userCompanies);

2. 让GetQueryable返回的IQueryable支持异步操作

普通List.AsQueryable()是Linq to Objects实现,不支持EF的异步扩展方法。你可以选以下两种方式解决:

方式一:使用EF Core内存数据库(推荐,贴近真实场景)

放弃Mock仓储,用InMemory数据库模拟真实查询逻辑,完全避免Mock Linq操作的问题:

// 创建内存数据库配置
var options = new DbContextOptionsBuilder<YourDbContext>()
    .UseInMemoryDatabase(databaseName: "TestLoginDb")
    .Options;

// 插入测试数据
using (var context = new YourDbContext(options))
{
    context.UserCompanies.AddRange(userCompanies);
    await context.SaveChangesAsync();
}

// 实例化真实仓储,传入内存上下文
var realRepo = new YourRepo(new YourDbContext(options));

// 将真实仓储注入userService,替换原Mock仓储
var userService = new UserService(_userManager.Object, realRepo);

方式二:使用异步Queryable扩展(必须Mock仓储时用)

安装NuGet包System.Linq.Async,将普通Queryable转换为支持异步的类型:

// 先安装NuGet包:System.Linq.Async
var userCompanies = new List<UserCompany> { new UserCompany { Id = 1, CompanyId = 1, UserId = 1 } };
// 转换为支持异步的IQueryable
var queryableUserCompanies = userCompanies.AsQueryable().AsAsyncQueryable();
_mockRepo.Setup(x => x.GetQueryable<UserCompany>()).Returns(queryableUserCompanies);

3. 验证Linq逻辑(可选)

如果需要验证仓储调用及Linq条件是否正确,可捕获返回的Queryable进行检查:

IQueryable<UserCompany> capturedQuery = null;
_mockRepo.Setup(x => x.GetQueryable<UserCompany>())
    .Callback(() => capturedQuery = userCompanies.AsQueryable().AsAsyncQueryable())
    .Returns(userCompanies.AsQueryable().AsAsyncQueryable());

// 执行测试
var result = await userService.LoginAsync(new UserLoginDTO { Email = email, Password = password });

// 验证Linq条件是否符合预期
var filteredIds = capturedQuery.AsNoTracking()
    .Where(c => c.UserId == 1)
    .Select(c => c.CompanyId)
    .ToList();
Assert.Equal(new List<int> {1}, filteredIds);

关于你自定义的扩展方法

你写的ToListAsync扩展未生效,是因为业务代码引用的是Microsoft.EntityFrameworkCore命名空间下的官方扩展,其优先级高于你自定义的扩展,测试时仍会调用官方静态方法,而静态方法无法被Mock。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 00:01:01