使用Moq测试API服务报错Value cannot be null (Parameter 'source')如何解决
错误产生原因
你遇到的Value cannot be null. (Parameter 'source')错误是LINQ操作触发的典型异常:当调用LINQ方法(比如Where、Select、ToList等)时,操作的数据源对象为null就会抛出该错误。对应到你的测试代码,具体原因如下:
- 核心原因:你虽然构造了
Mock<DbSet<MyModel>>对象,但没有为Mock的LiveDbContext配置对应MyModel实体的DbSet属性返回值。你的GetStaffByCentre方法内部必然是调用了LiveDbContext中类似DbSet<MyModel> Staff/DbSet<MyModel> MyModels的属性来做查询,你没有对该属性做Setup,代码运行时拿到的DbSet就是null,后续LINQ查询就会抛出source为null的错误。 - 无效配置干扰:你写的
mockContext.Setup(m => m.Add(models)).Callback<DbSet<MyModel>>(mockDbSet.Object.AddRange);是完全错误的配置,既不符合Mock DbContext的逻辑,参数匹配规则也不成立,属于完全无效的冗余代码,可能引入额外异常。 - 潜在异步问题:从你调用
.Result可以看出GetStaffByCentre是异步方法,你当前只配置了同步IQueryable的相关成员,就算解决了DbSet为null的问题,后续如果方法内部用到了EF异步查询方法(比如ToListAsync)也会抛出不支持异步操作的错误。
修复方案
按照以下步骤调整测试代码即可:
- 给Mock的DbContext配置对应DbSet属性的返回值,假设你的
LiveDbContext中对应MyModel的DbSet属性名为MyModels,添加以下配置:
// 注意替换MyModels为你DbContext中实际的属性名 mockContext.Setup(c => c.MyModels).Returns(mockDbSet.Object);
- 删除无效的冗余配置行:
// 直接删掉这行代码即可 mockContext.Setup(m => m.Add(models)).Callback<DbSet<MyModel>>(mockDbSet.Object.AddRange);
- (可选,适配异步查询)如果你的业务代码用到了EF异步查询方法,推荐安装
MockQueryable.MoqNuget包简化配置,无需手动编写IQueryable相关的Setup代码,调整后的Mock DbSet代码如下:
var models = new List<MyModel> { new MyModel { Id = 1, Name = "John Smith", Status = "Engineer", Centre = 9999 }, new MyModel { Id = 2, Name = "Jane Doe", Status = "Manager", Centre = 9999 } }; // 直接通过扩展方法生成适配同步+异步的Mock DbSet var mockDbSet = models.BuildMockDbSet(); mockContext.Setup(c => c.MyModels).Returns(mockDbSet.Object);
调整完成后重新运行测试即可解决当前报错。另外注意你的测试数据里有2条Centre=9999的记录,断言Assert.AreEqual(1, result.Count)大概率会失败,需要根据你的业务逻辑调整测试数据或者断言值。
内容的提问来源于stack exchange,提问作者George
相关产品推荐
相关产品推荐

