Erk*_* M. 9 c# testing unit-testing entity-framework moq
我试图理解单元测试中的模拟,并将单元测试过程集成到我的项目中.所以我一直走过几个教程并重构我的代码以支持模拟,无论如何,我无法通过测试,因为我试图测试的数据库方法是使用事务,但是在创建事务时,我得到了
底层提供程序在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;
}
Run Code Online (Sandbox Code Playgroud)
被测代码:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我也试图模仿交易部分:
var mockTransaction = new Mock<DbContextTransaction>();
mockContext.Setup(x => x.Database.BeginTransaction()).Returns(mockTransaction.Object);
Run Code Online (Sandbox Code Playgroud)
但这不起作用,失败了:
非虚拟(在VB中可覆盖)成员的无效设置:conn => conn.Database.BeginTransaction()
任何想法如何解决这个问题?
正如第二条错误消息所示,Moq无法模拟非虚方法或属性,因此这种方法不起作用.我建议使用适配器模式来解决这个问题.我们的想法是创建一个适配器(一个实现某个接口的包装类),它与之交互DataContext,并通过该接口执行所有数据库活动.然后,您可以改为模拟界面.
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();
}
}
Run Code Online (Sandbox Code Playgroud)
以前DataContext直接使用的所有代码现在应该使用a IDataContext,这应该是DataContextAdapter程序运行时的一个,但在测试中,您可以轻松地进行模拟IDataContext.这应该使模拟方式更简单,因为您可以设计IDataContext并DataContextAdapter隐藏实际的一些复杂性DataContext.
| 归档时间: |
|
| 查看次数: |
2642 次 |
| 最近记录: |