gpt4 book ai didi

c# - 通过 Entity Framework BeginTransaction

转载 作者:太空狗 更新时间:2023-10-29 19:40:50 26 4
gpt4 key购买 nike

我正在尝试理解单元测试中的模拟并将单元测试过程集成到我的项目中。所以我一直在浏览几个教程并重构我的代码以支持模拟,无论如何,我无法通过测试,因为我试图测试的数据库方法正在使用事务,但是在创建事务时,我得到

The underlying provider failed on Open.

没有事务一切正常。

我目前的代码是:

[TestMethod]
public void Test1()
{
var mockSet = GetDbMock();
var mockContext = new Mock<DataContext>();
mockContext.Setup(m => m.Repository).Returns(mockSet.Object);

var service = new MyService(mockContext.Object);
service.SaveRepository(GetRepositoryData().First());
mockSet.Verify(m => m.Remove(It.IsAny<Repository>()), Times.Once());
mockSet.Verify(m => m.Add(It.IsAny<Repository>()), Times.Once());
mockContext.Verify(m => m.SaveChanges(), Times.Once());
}

// gets the DbSet mock with one existing item
private Mock<DbSet<Repository>> GetDbMock()
{
var data = GetRepositoryData();
var mockSet = new Mock<DbSet<Repository>>();

mockSet.As<IQueryable<Repository>>().Setup(m => m.Provider).Returns(data.Provider);
// skipped for brevity
return mockSet;
}

被测代码:

private readonly DataContext _context;
public MyService(DataContext ctx)
{
_context = ctx;
}

public void SaveRepositories(Repository repo)
{
using (_context)
{
// Here the transaction creation fails
using (var transaction = _context.Database.BeginTransaction())
{
DeleteExistingEntries(repo.Id);
AddRepositories(repo);
_context.SaveChanges();
transaction.Commit();
}
}
}

我也试图模拟交易部分:

var mockTransaction = new Mock<DbContextTransaction>();
mockContext.Setup(x => x.Database.BeginTransaction()).Returns(mockTransaction.Object);

但这行不通,失败了:

Invalid setup on a non-virtual (overridable in VB) member: conn => conn.Database.BeginTransaction()

有什么解决办法吗?

最佳答案

如第二条错误消息所述,Moq 无法模拟非虚方法或属性,因此这种方法行不通。我建议使用 Adapter pattern解决这个问题。这个想法是创建一个与 DataContext 交互的适配器(一个实现某些接口(interface)的包装类),并通过该接口(interface)执行所有数据库事件。然后,您可以改为模拟界面。

public interface IDataContext {
DbSet<Repository> Repository { get; }
DbContextTransaction BeginTransaction();
}

public class DataContextAdapter {
private readonly DataContext _dataContext;

public DataContextAdapter(DataContext dataContext) {
_dataContext = dataContext;
}

public DbSet<Repository> Repository { get { return _dataContext.Repository; } }

public DbContextTransaction BeginTransaction() {
return _dataContext.Database.BeginTransaction();
}
}

之前直接使用 DataContext 的所有代码现在都应该使用 IDataContext,程序运行时它应该是 DataContextAdapter ,但在测试中,您可以轻松模拟 IDataContext。这也应该使模拟方式更简单,因为您可以设计 IDataContextDataContextAdapter 来隐藏实际 DataContext 的一些复杂性。

关于c# - 通过 Entity Framework BeginTransaction,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32554029/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com