【问题标题】:How to mock up dbcontext?如何模拟dbcontext?
【发布时间】:2016-06-04 13:03:06
【问题描述】:

我在 .net core 1.0 rc2 中使用实体框架 7。这是课程。

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {

    }
    public DbSet<Blog> Blogs { get; set; }
}

然后将ApplicationDbContext 注入到一个类中

public class BtnValidator
{
    private readonly ApplicationDbContext _dbContext;
    public BtnValidator(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }
}

不知道如何在单元测试方法中模拟它。

[Fact]
public void Ensure_Proper_Btn_Validated_Return_True()
{
    var dbContext = mockup(ApplicationDbContext); //how

    var validator = new BtnValidator(dbContext);
    var results = validator.IsValid("1234");
    Assure.True(results);
}

编辑

BtnValidator 中,我有访问dbContext 的代码。

public IsValid(string ID)
{
    var results = _dbContext.Blogs.First(x => x.ID);
    // 
}

【问题讨论】:

  • 这不是一个模拟,但请考虑为 EF 使用内存提供程序(努力 - effort.codeplex.com)。适合对 EF 相关代码进行单元测试。
  • @Evk,有两件事。一是我需要单元测试,二是我使用.Net core 1.0 rc2,库可能不支持它。
  • 也许此时对您来说不实用,但请考虑使用存储库模式。然后你模拟 repo,而不是实际的数据库访问。
  • @Crowcoder 我们使用工作单元模式,它将与我的数据库的各种表相对应的场景背后的存储库包装起来。对于测试场景,我们有一个名为 InMemoryUnitOfWork 的单独类,它代替真正的 UnitOfWork 类来管理内存中的所有存储库。内存存储库不依赖于真实数据库。

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


【解决方案1】:

您可以抽象 DbContext 以使其可模拟。

public interface IDbContext {
    DbSet<Blog> Blogs { get; set; }
    //...other properties and members needed for db context
    int SaveChanges();
}

public class ApplicationDbContext : DbContext, IDbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) {

    }

    public DbSet<Blog> Blogs { get; set; }
}

然后您可以将契约注入到依赖类中

public class BtnValidator {
    private readonly IDbContext _dbContext;

    public BtnValidator(IDbContext dbContext) {
        _dbContext = dbContext;
    }

    public bool IsValid(string ID) {
        var result = _dbContext.Blogs.FirstOrDefault(x => x.ID == ID);
        return result != null;
    }
}

然后在你的单元测试中你可以模拟接口

[Fact]
public void Ensure_Proper_Btn_Validated_Return_True() {
    //Arrange
    var id = "1234"
    var blogsTestData = new List<Blog>(){ new Blog { ID = id } };
    var blogs = MockDbSet(blogsTestData);
    //Set up mocks for db sets
    var dbContext = new Mock<IDbContext>();        
    dbContext.Setup(m => m.Blogs).Returns(blogs.Object);

    var validator = new BtnValidator(dbContext.Object);

    //Act
    var results = validator.IsValid(id);

    //Assert
    Assure.True(results);
}

Mock<DbSet<T>> MockDbSet<T>(IEnumerable<T> list) where T : class, new() {
    IQueryable<T> queryableList = list.AsQueryable();
    Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>();
    dbSetMock.As<IQueryable<T>>().Setup(x => x.Provider).Returns(queryableList.Provider);
    dbSetMock.As<IQueryable<T>>().Setup(x => x.Expression).Returns(queryableList.Expression);
    dbSetMock.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(queryableList.ElementType);
    dbSetMock.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(() => queryableList.GetEnumerator());
    dbSetMock.Setup(x => x.Create()).Returns(new T());

    return dbSetMock;
}

【讨论】:

  • 好主意。如果我没记错的话,Mock 是在 Moq Nuget 包中提供的。但是,在我的情况下,没有找到 x.Create() 方法。我安装了 Moq v4.16.1
猜你喜欢
  • 2017-08-04
  • 1970-01-01
  • 2018-06-09
  • 2018-08-15
  • 2019-06-10
  • 2015-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多