越过entity frameworkBeginTransaction

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

底层提供程序在Open上失败。

没有交易,一切正常。

我目前的代码是:

[TestMethod] public void Test1() { var mockSet = GetDbMock(); var mockContext = new Mock(); 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()), Times.Once()); mockSet.Verify(m => m.Add(It.IsAny()), Times.Once()); mockContext.Verify(m => m.SaveChanges(), Times.Once()); } // gets the DbSet mock with one existing item private Mock<DbSet> GetDbMock() { var data = GetRepositoryData(); var mockSet = new Mock<DbSet>(); mockSet.As<IQueryable>().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(); mockContext.Setup(x => x.Database.BeginTransaction()).Returns(mockTransaction.Object); 

但这不起作用,失败了:

非虚拟(在VB中可覆盖)成员的无效设置:conn => conn.Database.BeginTransaction()

任何想法如何解决这个问题?

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

 public interface IDataContext { DbSet Repository { get; } DbContextTransaction BeginTransaction(); } public class DataContextAdapter { private readonly DataContext _dataContext; public DataContextAdapter(DataContext dataContext) { _dataContext = dataContext; } public DbSet Repository { get { return _dataContext.Repository; } } public DbContextTransaction BeginTransaction() { return _dataContext.Database.BeginTransaction(); } } 

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