entity framework6和Moq4:是否有可能让模拟的DbSet在其范围的持续时间内保留添加的数据?

背景: – 使用EntityFramework 6 – 使用Moq v4.2.1402.2112 – 使用DbFirst方法

我一直在关注EF6 Moq演练(可以在这里找到); 我一直想知道是否有可能让一个模拟的DbSet保留在其范围的持续时间内添加到它的数据?

例如:

using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using System.Collections.Generic; using System.Data.Entity; using System.Linq; namespace TestingDemo { [TestClass] public class QueryTests { [TestMethod] public void GetAllBlogs_orders_by_name() { var data = new List { new Blog { Name = "BBB" }, new Blog { Name = "ZZZ" }, new Blog { Name = "AAA" }, }.AsQueryable(); var mockSet = new Mock<DbSet>(); mockSet.As<IQueryable>().Setup(m => m.Provider).Returns(data.Provider); mockSet.As<IQueryable>().Setup(m => m.Expression).Returns(data.Expression); mockSet.As<IQueryable>().Setup(m => m.ElementType).Returns(data.ElementType); mockSet.As<IQueryable>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator()); var mockContext = new Mock(); mockContext.Setup(c => c.Blogs).Returns(mockSet.Object); var service = new BlogService(mockContext.Object); service.AddBlog("YYY", "http://blogs.msdn.com/yyyy"); var blogs = service.GetAllBlogs(); Assert.AreEqual(4, blogs.Count); // Fails because whilst the AddBlog is called, and we can verify this, the AsQueryable List doesn't retain the new data Assert.AreEqual("AAA", blogs[0].Name); Assert.AreEqual("BBB", blogs[1].Name); Assert.AreEqual("YYY", blogs[2].Name); Assert.AreEqual("ZZZ", blogs[3].Name); } } } 

是否可以保留添加的数据,以便稍后在测试中查询?

您需要做的是对您希望修改集合的所有方法使用回调。 动态代理中的回调是在调用方法时运行的代码,并且可以访问参数。

创建一个临时集合来保存数据(如示例代码中的data )。 然后实现回调(1):对于可以修改集合的动态代理的每个方法 。 在这些回调中,修改您的临时集合( data )。 然后在动态代理中,模拟Count方法以从此集合( data )返回计数。

您的ad hoc集合已创建: data

(2)添加回调的方法是你的服务用来添加博客的方法, BlogService.AddBlog我不使用Moq4所以我不会告诉你语法,但是看看这里,在回调部分 ,并使用此语法添加所需的回调。

模拟具有许多方法和属性以及复杂行为(如DbSet是:

  • 你需要在你的dyanmic代理中实现很多回调:有多少方法可以修改集合,如(1)中所述
  • 或者你需要知道被测代码实现的细节,只实现必要的回调,如(2)哎呀! 那很难看。 您可以实现一些有效的方法,但测试可能会失败,因为您没有模拟所需的方法。

为避免此问题,您有两种解决方案。

  1. 创建一个包装EFfunction的界面。 模拟这个界面。 此解决方案限制了模拟方法的数量
  2. 使用内存数据库作为后端,以便您的测试类似于真正的数据库,您无需模拟任何内容。 您只需要为每个测试初始化​​内存中的db数据。 看这里 ,但不要只看待接受的答案(BTW不是最好的答案)。