如何使用moq模拟将项目添加到存储库或DbContext?

时间:2012-10-25 16:15:24

标签: entity-framework unit-testing moq

我见过的将moq用于存储库的示例仅显示了如何模拟返回的内容。我有一个奇怪的要求:当执行查询时,如果存在条件,则应该将某个项添加到存储库中。我想知道如何在不查询数据库的情况下测试它。我知道如何模拟现有的条件,但是如何设置模拟以便您可以测试是否添加了某个项?

5 个答案:

答案 0 :(得分:1)

尝试在内存存储库而不是moq中使用fake,例如所有实体的通用通用存储库:

public interface IInMemoryRepository<T> where T : class
{
    IQueryable<T> GetAll();
    void Create(T item);
    void Update(T item);
    T GetItem(Expression<Func<T, bool>> expression);
    void Delete(T item);
}

public class InMemoryRepository<T> : IInMemoryRepository<T> where T : class
{
    private int _incrementer = 0;
    public Dictionary<int, T> List = new Dictionary<int, T>();

    public IQueryable<T> GetAll()
    {
        return List.Select(x => x.Value).AsQueryable();
    }

    public void Create(T item)
    {
        _incrementer++;
        item.GetType().GetProperties().First(p => p.Name == "Id").SetValue(item, _incrementer, null);
        List.Add(_incrementer, item);
    }

    public void Update(T item)
    {
        var key = (int)item.GetType().GetProperties().First(p => p.Name == "Id").GetValue(item, null);
        List[key] = item;
    }

    public T GetItem(Expression<Func<T, bool>> expression)
    {
        return List.Select(x => x.Value).SingleOrDefault(expression.Compile());
    }

    public void Delete(T item)
    {
        var key = (int)item.GetType().GetProperties().First(p => p.Name == "Id").GetValue(item, null);
        List.Remove(key);
    }
}

答案 1 :(得分:1)

This blog article might be of use,虽然自从我撰写帖子后我的设计有所改变,但我确实需要更新它。我以一种能够模拟DbContext的方式使用了通用存储库模式。这允许数据访问层“直到边缘”进行测试。 Generic Repository and Unit of Work

答案 2 :(得分:0)

你不会嘲笑存储库;您将拥有一个使用内存存储而不是数据库的备用存储库,然后使用IoC为测试/代码选择正确的存储库实现。

答案 3 :(得分:0)

时代已经发生变化 - 自Entity Framework 6发布以来,模拟数据库上下文和数据集变得更加容易。 This article outlines the particulars

测试非查询方案

// @flow
type Props = {
  width: string,
};

function fun({ width = '30em' }: Props) {
  return width;
}

测试查询方案 查询测试现在非常好,因为您可以在代码中构建测试数据集,然后针对它们执行测试:

using Microsoft.VisualStudio.TestTools.UnitTesting; 
using Moq; 
using System.Data.Entity; 

namespace TestingDemo 
{ 
    [TestClass] 
    public class NonQueryTests 
    { 
        [TestMethod] 
        public void CreateBlog_saves_a_blog_via_context() 
        { 
            var mockSet = new Mock<DbSet<Blog>>(); 

            var mockContext = new Mock<BloggingContext>(); 
            mockContext.Setup(m => m.Blogs).Returns(mockSet.Object); 

            var service = new BlogService(mockContext.Object); 
            service.AddBlog("ADO.NET Blog", "http://blogs.msdn.com/adonet"); 

            mockSet.Verify(m => m.Add(It.IsAny<Blog>()), Times.Once()); 
            mockContext.Verify(m => m.SaveChanges(), Times.Once()); 
        } 
    } 
}

答案 4 :(得分:0)

您可以通过模拟DbSet.Add()方法来做到这一点,就像这样:

[Fact]
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" },
  };
  
  var mockSet = new Mock<DbSet<Blog>>();
  mockSet.Setup(blogs => blogs.Add(It.IsAny<Blog>)).Returns<Blog>(blog =>
  {
    data.Add(blog);
    return blog;
  });
  
  var mockContext = new Mock<BloggingContext>();
  mockContext.Setup(m => m.Blogs).Returns(mockSet.Object);
  
  var service = new BlogService(mockContext.Object);
  var blog = service.AddBlog("_ADO.NET Blog", "http://blogs.msdn.com/adonet");
  var blogs = service.GetAllBlogs();
  
  mockSet.Verify(m => m.Add(It.IsAny<Blog>()), Times.Once());
  mockContext.Verify(m => m.SaveChanges(), Times.Once());
  
  Assert.NotNull(blog)
  Assert.Equal(4, blogs.Count);
  Assert.Equal("AAA", blogs(1).Name);
  Assert.Equal("BBB", blogs(2).Name);
  Assert.Equal("ZZZ", blogs(3).Name);
}

这是根据here找到的文档改编而成的。