使用事务NUnit和NSubstitute时如何模拟UnitOfWork

问题描述

我已经使用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和存储库,现在看来可以测试了。