【问题标题】:EF Mock of dbContext dont use eager loadingdbContext 的 EF Mock 不使用急切加载
【发布时间】:2016-06-21 17:46:07
【问题描述】:

我尝试使用 NUnit 和 Moq 对访问数据的服务进行单元测试。我像这样创建 DbContext 的模拟:

我的实体和上下文

 public class BloggingContext : DbContext
{
    public virtual DbSet<Blog> Blogs { get; set; }
    public virtual DbSet<Post> Posts { get; set; }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }

    public virtual List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public virtual Blog Blog { get; set; }
}

测试方法:

public void CreateBlog_saves_a_blog_via_context()
    {
       var data = new List<Blog>
        {
            new Blog { Name = "BBB" },
            new Blog { Name = "ZZZ" },
            new Blog { Name = "AAA" },
        }.AsQueryable();

        var data2 = new List<Blog>
        {
            new Post{ Title= "BBB" },
            new Post{ Title= "ZZZ" },
            new Post{ Title= "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 mockSet2 = new Mock<DbSet<POs>>();
        mockSet2.As<IQueryable<Blog>>().Setup(m => m.Provider).Returns(data2.Provider);
        mockSet2.As<IQueryable<Blog>>().Setup(m => m.Expression).Returns(data2.Expression);
        mockSet2.As<IQueryable<Blog>>().Setup(m => m.ElementType).Returns(data2.ElementType);
        mockSet2.As<IQueryable<Post>>().Setup(m => m.GetEnumerator()).Returns(data2.GetEnumerator());

        var mockContext = new Mock<BloggingContext>();
        mockContext.Setup(c => c.Blogs).Returns(mockSet.Object);
        mockContext.Setup(c => c.Posts).Returns(mockSet2.Object);
        var service = new BlogService(mockContext.Object);
        var blogs = service.GetAllBlogs();
    }

但是当我不想设置实体之间的关系时,我会测试它们

Post = new Post(){
  Title ="",
  Content = "",
  BlogID = 2
};

但是在测试中没有设置导航属性(在正常设置中它的设置)。当我尝试从上下文中阅读这篇文章时,我总是有 null,但 BlogID 已经设置。

【问题讨论】:

  • 我认为你有一个复制粘贴错误 ar data2 = new List 应该是 Post 正确的?
  • 你必须在博客集合中设置 new Blog { Name = "BBB" , Posts = new List() { new Post{ Title= "BBB" },..... } },

标签: c# entity-framework unit-testing mocking moq


【解决方案1】:

我会以不同的方式对此进行单元测试,查看单元测试的名称,您只是试图确保在创建博客时,将正确的数据传递到 DbContext.. 您可以按如下方式执行此操作;

   [TestMethod]
    public void CreateBlog_saves_a_blog_via_context()
    {
        var mockContext = new Mock<BloggingContext>();

        // Add related posts directly into fake blog data
        var data = new List<Blog>
        {
            new Blog {Name = "BBB", Posts = new List<Post>() { new Post() { Title = "Post1"} } },
            new Blog {Name = "ZZZ", Posts = new List<Post>() { new Post() { Title = "Post2"} } },
            new Blog {Name = "AAA", Posts = new List<Post>() { new Post() { Title = "Post3"} } },
        }.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());

        mockContext.Setup(c => c.Blogs).Returns(mockSet.Object);

        var service = new BlogService(mockContext.Object);

        var newBlog = new Blog {Name = "A New Blog", Posts = new List<Post>() {new Post() {Title = "Post1"}}};

        // Add new Blog to service
        service.AddBlog(newBlog);

        // Check that DbContext received the new blog correctly
        // And Blog contained correct name and Post count of 1
        mockSet.Verify(x=>x.Add(It.Is<Blog>(blog=>blog.Name == "A New Blog" && blog.Posts.Count == 1)));
    }

我希望您能看到,您正在确保您的测试类正确地将正确的对象传递给 DbContext。您现在还可以进行其他断言,例如确认 DbContext 中的 SaveChanges() 方法也只被调用过一次。

测试你的类,而不是 DbContext

【讨论】:

  • 哦,谢谢,我早知道了,但我会喜欢你的工作。祝你有美好的一天!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多