起订量,让过去的实体框架的BeginTransaction [英] Moq, getting past entity framework BeginTransaction
问题描述
我试图让嘲弄在单元测试的意识和单元测试过程集成到我的项目。所以,我一直走直通几个教程和重构我的代码,以支持嘲讽,反正我是无法通过测试,因为DB方法,我想测试使用事务,但创建一个交易的时候,我得到
I am trying to make sense of mocking in unit testing and to integrate the unit testing process to my project. So I have been walking thru several tutorials and refactoring my code to support mocking, anyway, I am unable to pass the tests, because the DB method I am trying to test is using a transaction, but when creating a transaction, I get
基础提供开放式失败。
如果没有交易一切正常就好了。
Without transaction everything works just fine.
我目前拥有的代码是:
[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();
}
}
}
我试图嘲弄交易部分,以及:
I was trying to mock the transaction part as well:
var mockTransaction = new Mock<DbContextTransaction>();
mockContext.Setup(x => x.Database.BeginTransaction()).Returns(mockTransaction.Object);
但这不是工作,与失败的:
but this is not working, failing with:
非虚拟(VB中重写)成员无效设置:康恩=>
conn.Database.BeginTransaction()
Invalid setup on a non-virtual (overridable in VB) member: conn => conn.Database.BeginTransaction()
任何想法如何解决这个问题?
Any ideas how to solve this?
推荐答案
作为第二个错误消息称,最小起订量无法模拟非虚方法或属性,所以这种做法是行不通的。我建议使用适配器模式来解决这个问题。我们的想法是创建一个适配器的与相互作用(即实现了一些接口的包装类)在的DataContext
,并通过执行所有数据库活动接口。然后,你可以嘲笑接口而不是
As the second error message says, Moq can't mock non-virtual methods or properties, so this approach won't work. I suggest using the Adapter pattern to work around this. The idea is to create an adapter (a wrapper class that implements some interface) that interacts with the DataContext
, and to perform all database activity through that interface. Then, you can mock the interface instead.
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();
}
}
你的所有代码,以前使用的<$ C的$ C>的DataContext 直接现在应该使用 IDataContext
,这应该是一个 DataContextAdapter
时在程序运行,但在测试中,你可以很容易地嘲笑 IDataContext
。这应该使嘲讽方式更简单一点,因为你可以设计 IDataContext
和 DataContextAdapter
来隐藏一些实际的复杂性的DataContext
。
All of your code that previously used the DataContext
directly should now use an IDataContext
, which should be a DataContextAdapter
when the program is running, but in a test, you can easily mock IDataContext
. This should make the mocking way simpler too because you can design IDataContext
and DataContextAdapter
to hide some of the complexities of the actual DataContext
.
这篇关于起订量,让过去的实体框架的BeginTransaction的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!