Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实体框架6和Moq4:模拟数据库集是否可以在其范围内保留添加的数据?_C#_Entity Framework_Moq - Fatal编程技术网

C# 实体框架6和Moq4:模拟数据库集是否可以在其范围内保留添加的数据?

C# 实体框架6和Moq4:模拟数据库集是否可以在其范围内保留添加的数据?,c#,entity-framework,moq,C#,Entity Framework,Moq,背景: -使用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.Entit

背景: -使用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<Blog> 
            { 
                new Blog { Name = "BBB" }, 
                new Blog { Name = "ZZZ" }, 
                new Blog { Name = "AAA" }, 
            }.AsQueryable(); 

            var mockSet = new Mock<DbSet<Blog>>(); 
            mockSet.As<IQueryable<Blog>>().Setup(m => m.Provider).Returns(data.Provider); 
            mockSet.As<IQueryable<Blog>>().Setup(m => m.Expression).Returns(data.Expression); 
            mockSet.As<IQueryable<Blog>>().Setup(m => m.ElementType).Returns(data.ElementType); 
            mockSet.As<IQueryable<Blog>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator()); 

            var mockContext = new Mock<BloggingContext>(); 
            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); 
        } 
    } 
}
使用Microsoft.VisualStudio.TestTools.UnitTesting;
使用最小起订量;
使用System.Collections.Generic;
使用System.Data.Entity;
使用System.Linq;
命名空间测试演示
{ 
[测试类]
公共类查询测试
{ 
[测试方法]
public void GetAllBlogs\u orders\u by\u name()
{ 
var数据=新列表
{ 
新博客{Name=“BBB”},
新博客{Name=“ZZZ”},
新博客{Name=“AAA”},
}.AsQueryable();
var mockSet=new Mock();
mockSet.As().Setup(m=>m.Provider).返回(data.Provider);
mockSet.As().Setup(m=>m.Expression).Returns(data.Expression);
mockSet.As().Setup(m=>m.ElementType).Returns(data.ElementType);
mockSet.As().Setup(m=>m.GetEnumerator()).Returns(data.GetEnumerator());
var mockContext=new Mock();
Setup(c=>c.Blogs).Returns(mockSet.Object);
var service=newblogservice(mockContext.Object);
service.AddBlog(“YYY”http://blogs.msdn.com/yyyy"); 
var blogs=service.GetAllBlogs();
Assert.AreEqual(4,blogs.Count);//失败,因为在调用AddBlog时,我们可以验证这一点,但AsQueryable列表不保留新数据
Assert.AreEqual(“AAA”,博客[0].Name);
Assert.AreEqual(“BBB”,blogs[1].Name);
Assert.AreEqual(“YYY”,blogs[2].Name);
Assert.AreEqual(“ZZZ”,blogs[3].Name);
} 
} 
}

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

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

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

您的临时集合已创建:
数据

(2) 添加回调的方法是您的服务用于添加blog的方法,
BlogService.AddBlog
我不使用Moq4,因此我不会向您显示语法,而是使用此语法添加所需的回调

模拟具有许多方法和属性以及复杂行为(如
DbSet
)的对象的问题是:

  • 您需要在动态代理中实现大量回调:有多少方法可以修改集合,如(1)所述
  • 或者您需要了解测试代码的实现细节,以便只实现必要的回调,如(2)Oops!那太难看了。您可以实现一些有效的方法,但是测试可能会失败,因为您没有模拟所需的方法
要避免这个问题,您有两种解决方案

  • 创建一个界面来包装EF功能。模拟此接口。此解决方案限制了要模拟的方法的数量
  • 使用内存中的数据库作为后端,以便您的测试类似于真实的数据库,并且无需模拟任何内容。您只需要为每个测试初始化内存中的db数据。 ,但不要只看公认的答案(顺便说一句,哪一个不是最好的答案)

  • 您可以在模拟机上尝试
    CallBase=true
    var mockSet=newmock{CallBase=true}所以moq将调用DbSet的Add方法。感谢您的回复,但是这似乎没有帮助;我是否需要为add函数设置某种链接以添加到基础列表中?回调是我所问问题的答案,这非常适合基本单元测试;然而,关于内存中数据库实现的额外信息非常有用。我现在正在研究用于更复杂的集成测试。是的,使用内存中的DB使测试更容易:您不必为EF上下文编写mock(事实上,有一些mock很难实现,即使用几个
    Include()
    模拟查询,或者使用相关实体更新实体:使用内存中的,这非常容易)。此外,测试的运行速度将与使用模拟的单元测试一样快,因为它们不会达到真正的DB或需要在磁盘上读/写。(我仍然更喜欢将EF与接口解耦,并模拟这些接口,因为我使用不同的体系结构,并且盲目地依赖真实的接口实现)