问题描述
我已经使用ASP.NET Core 3.1和EF Core 5.0创建了一个Web API。数据存储在MSsql数据库中。 我已经实现了UnitOfWork和存储库模式。
UnitOfWork类具有用于创建事务的方法,它看起来像这样:
//UnitOfWork
public async Task ExecuteTransaction(Func<Task> insideTransactionFunction)
{
var transaction = await _context.Database.BeginTransactionAsync();
try
{
await insideTransactionFunction();
await transaction.CommitAsync();
}
catch (Exception)
{
await transaction.RollbackAsync();
throw;
}
}
我正在尝试为使用UnitOfWork类修改sql数据库中数据的服务类编写测试。使用UserService添加用户时的Fx:
//UserService
public async Task<User> AddUserAsync(User user)
{
await _unitOfWork.ExecuteTransaction(async () =>
{
//Add user locally to generate the local id
_unitOfWork.UserRepository.Add(user);
await _unitOfWork.SaveChangesAsync();
//...some logic that uses the generated user id...
if(string.IsNullOrWhiteSpace(email.User) == false)
{
//Inviting the user returns the generated Azure User id
user.AzureUserId = _azureService.InviteUser(user.Email);
await _unitOfWork.SaveChangesAsync();
}
}
return user;
}
对上述方法的测试如下:
//UserServiceTests
public async Task AddUserAsync_UserQualifiesForAzureInvite_AzureUserIdSetonCreatedUser()
{
//Arrange
var unitOfWork = Substitute.For<IUnitOfWork>();
var azureService = Substitute.For<IAzureService>();
var uut = new UserService(unitOfWork,azureService);
var newUser = new User { ... some setup ... };
var azureUserId = Guid.NewGuid();
azureService.InviteUser(null).ReturnsForAnyArgs(Task.Fromresult(azureUserId));
//Act
var createdUser = await _uut.AddUserAsync(newUser); //Returns right away
//Assert
Assert.That(createdUser.AzureUserId,Is.EqualTo(azureUserId));
}
问题是使用UnitOfWork创建的事务将被忽略,并且用户将立即返回。
public async Task<User> AddUserAsync(User user)
{
//Skipped from here...
await _unitOfWork.ExecuteTransaction(async () =>
{
//
}
//...To here
return user;
}
所以我的问题是:我该如何模拟UnitOfWork类并且仍然能够测试事务中包装的代码?
解决方法
我的体系结构存在根本缺陷。查看Panagiotis Kanavos的评论和链接。
解决方案是摆脱UnitOfWork和存储库,现在看来可以测试了。