我正在学习单元测试中的模拟,并尝试将单元测试过程集成到我的项目中。因此,我已经浏览了几个教程并重构了我的代码以支持模拟。然而,由于我尝试测试的DB方法使用了事务,所以我无法通过测试。但是当我创建一个事务时,我遇到了以下错误:
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);
但是这并不起作用,会失败并显示以下错误:
在非虚拟成员(在 VB 中可以重写)上进行无效的设置:conn => conn.Database.BeginTransaction()
有什么想法解决这个问题吗?
DbContextTransaction
,因为它只有内部构造函数,这似乎是Moq
的一个问题。不管怎样,测试执行似乎并不真正依赖于它的工作,如果我在没有调试的情况下运行测试,它们会通过,除非我明确检查是否抛出了任何异常。这很好。感谢您的见解,除非有更好的方法出现,否则我将接受这个方案。(y) - Erki M.IDbContextTransaction
接口,由DbContextTransactionAdapter
实现,它包装了一个实际的DbContextTransaction
- 并在测试中模拟IDbContextTransaction
。这有点麻烦,但这个技巧通常会使使用库代码的代码更容易测试,并且与库的耦合度更低。 - Aasmund Eldhuset