使用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
相关产品推荐
相关产品推荐

