Moq DbSet NotImplementedException

5

我有一个 Moq 的 DbSet,在最近更新依赖项后一直工作正常,但现在调用 IQueryable.Provider 时抛出了一个 NotImplementedException 异常。

代码如下:

var mockSet = new Mock<DbSet<A>>();
var list = new List<A>();
var queryable = list.AsQueryable();
mockSet.As<IQueryable<A>>().Setup(m => m.Provider).Returns(queryable.Provider);
mockSet.As<IQueryable<A>>().Setup(m => m.Expression).Returns(queryable.Expression);
mockSet.As<IQueryable<A>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
mockSet.As<IQueryable<A>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());

var f =mockSet.Object.FirstOrDefault(); // NotImplementedException thrown here

以下是抛出的异常:
System.NotImplementedException
The member 'IQueryable.Provider' has not been implemented on type
'DbSet`1Proxy_1' which inherits from 'DbSet`1'.
Test doubles for 'DbSet`1' must provide implementations of methods
and properties that are used.

1
这篇微软文章提供了一种实现方式,允许您使用内存中的测试替身。我刚刚更新了我的 Moq 4.7.99 和 Castle.Core 4.1.1,我的测试通过了。https://msdn.microsoft.com/en-us/library/dn314431(v=vs.113).aspx - Jasen
这很有帮助。不幸的是,我经常发现更高级的MSDN文章基本上只是被转化为一个庞大的列表。 - Kanadaj
使用Sqlite内存数据库将提供更好的测试体验,因为您不会受到如何构建查询的限制。只需插入所需数据,运行查询,检查预期结果即可。 - Fabio
2个回答

4
您可能一直在使用Moq的版本4.7.58。该特定版本受到回归的影响,会触发NotImplementedException。该回归已在版本4.7.63中修复,因此建议您将Moq包引用更新至版本4.7.63或更高版本以解决此问题。
您的代码在Moq 4.7.58之前的版本中可以正常工作,原因是由于一个“功能”,但这个“功能”带来的问题比它解决的问题还要多。因此,该功能已被撤消
Moq已恢复到其原始行为,即在这种特定情况下需要通过mock.As<TInterface>设置各个接口成员,在调用mock.Object之前进行设置。 (通常,在检索模拟对象后执行更多设置也很好;但这种情况是一个显着的例外。希望在未来的Moq版本中可以解决这个问题。)

这是否意味着在这种情况下我基本上必须使用mock.As<IQueryable>().Object?根据我的Git历史记录,问题发生在Moq 4.7.99和Castle.Core 4.1.1.0中,代码与上面提供的完全相同。 - Kanadaj
从4.7.25升级到4.7.99后,问题再次出现。 - Kanadaj
@DanielRusznyak:根据您上面发布的代码,并使用Moq 4.7.99,我无法重现您所说的错误。它可以编译和运行而不出现任何错误。您确定在重现代码中没有遗漏任何内容吗?您的目标实体框架版本是什么? - stakx - no longer contributing
实际上,在调查后,问题是在Provider设置之前有一个杂散的mock.Object.Add()调用,它在完全不同的地方抛出了错误。旧版本忽略了这个问题,然而新版本在下一个mock.Object.FirstOrDefault()失败并抛出了一个NotImplementedException,没有指出真正的问题所在。 - Kanadaj
回复:_"问题是在setup之前有一个杂散的mock.Object.Add()调用"_ - 是的,根据第三段,那就是问题所在。回复:_"旧版本忽略了这个问题"_ - 它没有忽略它;事实上,我回答的第二段中提到的有问题的功能正是使得在EF测试中能够早期调用mock.Object的功能(以牺牲破坏大量其他同样可能使用情况)的原因。 - stakx - no longer contributing

0
将Castle.Core回滚到4.0.0版本并将Moq更新到支持4.0.0的最新版本解决了这个问题。我仍然在想是否有什么我错过的东西可以在新版本中修复这个问题。

新版本(指目前的4.7.99)已经修复了这个问题。实际上,你的代码也可以在版本4.7.63中运行;请参考我的回答 - stakx - no longer contributing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接