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

使用Moq与NUnit模拟DbContext时遇无参构造函数缺失错误求解决

问题排查与解决方案

错误原因

报错核心:Moq无法为ApplicationDbContext创建代理类,因为该类没有无参构造函数。Moq模拟类类型时,默认会尝试调用无参构造函数实例化目标类,但ApplicationDbContext通常仅实现了带DbContextOptions<ApplicationDbContext>参数的构造函数,无无参构造,导致Castle动态代理无法生成代理实例。

另外,观察UpvoteController.GetUpvotes()方法,代码完全未用到注入的_context对象,属于冗余依赖,无需在测试中模拟。

解决方案

1. 移除控制器冗余DbContext依赖

既然控制器逻辑未用到ApplicationDbContext,直接从构造函数中删除该参数,减少不必要依赖:

public UpvoteController(IMapper mapper, 
            IUnitOfWork unitOfWork, ILogger<UpvoteController> logger)
{
    _mapper = mapper;
    _unitOfWork = unitOfWork;
    _logger = logger;
}

2. 修复测试代码逻辑问题

测试方法中创建了新的unitOfWork模拟实例,但未注入到控制器,导致控制器仍使用Setup中旧的_unitOfWork(返回的是Mock<IRepository<Upvote>>,而非自定义的UpvoteTestRepository)。需在测试中重新实例化控制器,传入正确依赖:

修改后的测试方法:

[Test]
public void GetAllUpVotes_SendRequest_ReturnListOfUpVotes()
{
    // 准备测试数据
    List<Upvote> expectedResult = new List<Upvote> {upvote_one, upvote_two};
    var repo = new UpvoteTestRepository(expectedResult);
    
    // 配置UnitOfWork模拟
    var unitOfWork = new Mock<IUnitOfWork>();
    unitOfWork.SetupGet(work => work.Upvotes).Returns(repo);
    
    // 配置Mapper模拟(控制器会调用Map方法)
    var mapper = new Mock<IMapper>();
    mapper.Setup(m => m.Map<IList<UpvoteDTO>>(It.IsAny<IList<Upvote>>()))
          .Returns(new List<UpvoteDTO>()); // 可按需返回对应DTO列表
    
    // 重新实例化控制器,传入正确依赖
    var controller = new UpvoteController(mapper.Object, unitOfWork.Object, _logger.Object);
    
    // 执行测试方法
    var result = controller.GetUpvotes().GetAwaiter().GetResult();
    
    // 断言
    Assert.IsInstanceOf<OkObjectResult>(result);
    Assert.IsNotEmpty(repo.Source);
    CollectionAssert.AreEqual(expectedResult, repo.GetAll().GetAwaiter().GetResult());
}

3. 若确实需要模拟DbContext(可选)

如果后续控制器需用到ApplicationDbContext,可通过以下两种方式解决:

  • 给ApplicationDbContext添加无参构造函数(仅用于测试,生产环境不推荐):
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext() { } // 测试用无参构造
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
    // ... DbSet定义
}
  • 使用Moq指定构造函数参数:
// 创建空的DbContextOptions
var options = new DbContextOptions<ApplicationDbContext>();
// 用构造函数参数模拟DbContext
_context = new Mock<ApplicationDbContext>(options);

优化后的测试类Setup方法

[SetUp]
public void Setup()
{
    var config = new MapperConfiguration(cfg =>
    {
        cfg.AddProfile<MapperInitilizer>();
    });
    _realMapper = new Mapper(config);
    _logger = new Mock<ILogger<UpvoteController>>();
    
    // 初始化测试数据
    upvote_one = new Upvote()
    {
        Id = 1,
        UserId = "43434343434",
        TopicId = 1
    };
  
    upvote_two = new Upvote()
    {
        Id = 2,
        UserId = "65664535",
        TopicId = 2
    };

    user_one = new User()
    {
        Id = "43434343434",
        FirstName = "john",
        LastName = "doe",
        Email = "john@gmail.com",
        Photo = "hgghghg",
        PhoneNumber = "fgfffgfg"
    };
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 20:24:32