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

使用Moq模拟ProjectDbContext时报Unsupported expression错误如何解决

问题原因及解决步骤

1. 两个报错的根本原因

  • 第一个Non-overridable members报错:Moq 只能对虚成员做Setup配置,默认实现的DbSet属性没有加virtual修饰,无法被重写代理。
  • 第二个Can not instantiate proxy of class报错:你的ProjectDbContext只有带DbContextOptions<ProjectDbContext>参数的构造函数,直接实例化Mock<ProjectDbContext>时没有传入对应构造参数,动态代理无法生成实例。

2. 具体修正代码

第一步:修正ProjectDbContext定义,给DbSet加virtual修饰
public class ProjectDbContext : DbContext
{
    // 加virtual修饰支持Mock重写
    public virtual DbSet<Item> Items { get; set; }

    public ProjectDbContext(DbContextOptions<ProjectDbContext> opt) : base(opt)
    {}
}
第二步:修正测试类的Mock初始化逻辑
public class ItemTest
{
    private readonly Mock<DbSet<Item>> _mockSet = new Mock<DbSet<Item>>();
    private Mock<ProjectDbContext> _mockContext;

    public ItemTest()
    {
        // 构造Mock时传入DbContextOptions参数,匹配ProjectDbContext的构造函数要求
        var options = new DbContextOptionsBuilder<ProjectDbContext>().Options;
        _mockContext = new Mock<ProjectDbContext>(options);
        _mockContext.Setup(m => m.Items).Returns(_mockSet.Object);
    }

    [Fact]
    public void GetById_ShouldReturnItemWhenItemExists()
    {
        // Arrange
        var itemId = Guid.NewGuid();
        var testItem = new Item { Id = itemId };
        // 配置Mock DbSet的IQueryable实现,支持LINQ查询操作
        var data = new List<Item> { testItem }.AsQueryable();
        _mockSet.As<IQueryable<Item>>().Setup(m => m.Provider).Returns(data.Provider);
        _mockSet.As<IQueryable<Item>>().Setup(m => m.Expression).Returns(data.Expression);
        _mockSet.As<IQueryable<Item>>().Setup(m => m.ElementType).Returns(data.ElementType);
        _mockSet.As<IQueryable<Item>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
        
        // 初始化服务
        var repository = new ItemsService(_mockContext.Object);

        // Act
        // 移除多余的CancellationToken参数,和IItemsService定义的GetById方法签名保持一致
        var item = repository.GetById(itemId);

        // Assert
        Assert.Equal(itemId, item.Id);
    }
}

3. 可选优化方案

如果不想给DbContext的所有DbSet都加virtual修饰,可以直接用EF Core自带的内存数据库做测试,不需要Mock DbContext,代码更简洁,也更贴合真实的数据库操作逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 06:06:02