entity framework6模拟包括dbset上的方法

一直在谷歌搜索有关如何在EF6中模拟dbset上的include方法的问题的解决方案。 问题在这里有详细记载: –

http://entityframework.codeplex.com/discussions/461731

不幸的是,虽然那里似乎没有有效的解决方案。

有人找到了解决方法吗?

我确实理解我们不应该真的嘲笑EF6环境,但项目负责人坚持要求。

提前致谢。

所以,如果有点冒险,这是可能的!

在下面我设置模拟上下文和设置,并可以成功调用包含。 我认为秘诀就是将调用存根到Provider,Expression和GetEnumerator,并将存根上下文中的DbSet属性设置为存根集,而不是将上下文存根到返回它们。

GitHub上提供了一个可运行的示例

[Test] public void CanUseIncludeWithMocks() { var child = new Child(); var parent = new Parent(); parent.Children.Add(child); var parents = new List { parent }.AsQueryable(); var children = new List { child }.AsQueryable(); var mockContext = MockRepository.GenerateStub(); var mockParentSet = MockRepository.GenerateStub>(); var mockChildSet = MockRepository.GenerateStub>(); mockParentSet.Stub(m => m.Provider).Return(parents.Provider); mockParentSet.Stub(m => m.Expression).Return(parents.Expression); mockParentSet.Stub(m => m.GetEnumerator()).Return(parents.GetEnumerator()); mockChildSet.Stub(m => m.Provider).Return(children.Provider); mockChildSet.Stub(m => m.Expression).Return(children.Expression); mockChildSet.Stub(m => m.GetEnumerator()).Return(children.GetEnumerator()); mockContext.Parents = mockParentSet; mockContext.Children = mockChildSet; mockContext.Parents.Should().HaveCount(1); mockContext.Children.Should().HaveCount(1); mockContext.Parents.First().Children.FirstOrDefault().Should().NotBeNull(); var query = mockContext.Parents.Include(p=>p.Children).Select(pc => pc); query.Should().NotBeNull().And.HaveCount(1); query.First().Children.Should().NotBeEmpty().And.HaveCount(1); } 

我和上面的@GetFuzzy有同样的戏剧 – 似乎无论我做什么,只要在Moq DbSet上进行Include()调用,我就无法避免NullReferenceException。 遗憾的是,另一个答案中的Github示例不起作用:Set.Include()始终返回null。

在摆弄了一段时间之后,我想出了一个解决方法。

 [Test] public void CanUseIncludeWithMocks() { var child = new Child(); var parent = new Parent(); parent.Children.Add(child); var parents = new List { parent }; var children = new List { child }; var parentsDbSet1 = new FakeDbSet(); parentsDbSet1.SetData(parents); var parentsDbSet2 = new FakeDbSet(); parentsDbSet2.SetData(parents); parentsDbSet1.Setup(x => x.Include(It.IsAny())).Returns(parentsDbSet2.Object); // Can now test a method that does something like: context.Set().Include("Children") etc } public class FakeDbSet : Mock> where T : class { public void SetData(IEnumerable data) { var mockDataQueryable = data.AsQueryable(); As>().Setup(x => x.Provider).Returns(mockDataQueryable.Provider); As>().Setup(x => x.Expression).Returns(mockDataQueryable.Expression); As>().Setup(x => x.ElementType).Returns(mockDataQueryable.ElementType); As>().Setup(x => x.GetEnumerator()).Returns(mockDataQueryable.GetEnumerator()); } } 

我真的不喜欢必须有两个假DbSets的笨拙但由于某种原因这不起作用:

 parentsDbSet1.Setup(x => x.Include(It.IsAny())).Returns(parentsDbSet1.Object); 

有人对此有解释吗?

使用Moq框架,这个方法适用于我抛出的所有东西。

  public static Mock> GetMockSet(this ObservableCollection list) where T : class { var queryable = list.AsQueryable(); var mockList = new Mock>(MockBehavior.Loose); mockList.As>().Setup(m => m.Provider).Returns(queryable.Provider); mockList.As>().Setup(m => m.Expression).Returns(queryable.Expression); mockList.As>().Setup(m => m.ElementType).Returns(queryable.ElementType); mockList.As>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator()); mockList.Setup(m => m.Include(It.IsAny())).Returns(mockList.Object); mockList.Setup(m => m.Local).Returns(list); mockList.Setup(m => m.Add(It.IsAny())).Returns((T a) => { list.Add(a); return a; }); mockList.Setup(m => m.AddRange(It.IsAny>())).Returns((IEnumerable a) => { foreach (var item in a.ToArray()) list.Add(item); return a; }); mockList.Setup(m => m.Remove(It.IsAny())).Returns((T a) => { list.Remove(a); return a; }); mockList.Setup(m => m.RemoveRange(It.IsAny>())).Returns((IEnumerable a) => { foreach (var item in a.ToArray()) list.Remove(item); return a; }); return mockList; } 

使用它只是做:

  mockContext.Setup(p => p.).Returns(.GetMockSet().Object);` 

如果上下文实现了一个接口,那么这就好了,因为你永远不需要对EF做任何事情。

编辑:

额外位的原因是我们可以检查测试结果,如果我们添加或删除,我们可以检查传递的集合,它将在测试后得到结果。