Moq的Xunit和Mock数据 [英] Xunit and Mock data with Moq

查看:61
本文介绍了Moq的Xunit和Mock数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是单元测试的新手,任何人都可以建议如何使用xUnit和Moq在下面测试公共方法(CreateUser),谢谢!

I'm new to unit testing, can anyone advise how to test public method (CreateUser) below using xUnit and Moq, thanks!

public async Task<bool> CreateUser(UserDTO newUser)
{
  newUser.CustomerId = _userResolverService.GetCustomerId();
  if (await CheckUserExists(newUser)) return false;
  var salt = GenerateSalt(10);
  var passwordHash = GenerateHash(newUser.Password, salt);

  await _usersRepository.AddAsync(new User()
  {
    Role = newUser.Role,
    CretedOn = DateTime.Now,
    CustomerId = newUser.CustomerId,
    Email = newUser.Email,
    FirstName = newUser.FirstName,
    LastName = newUser.LastName,
    PasswordHash = passwordHash,
    Salt = salt,
    UpdatedOn = DateTime.Now
  });

  return true;
}

下面的私人方法检查用户是否存在,只是返回现有用户数

Private methods below Check if user exists simply returns number of existing users

private async Task<bool> CheckUserExists(UserDTO user)
    {
      var users = await _usersRepository.GetAllAsync();
      var userCount = users.Count(u => u.Email == user.Email);
      return userCount > 0;
    }

哈希生成

private static string GenerateHash(string input, string salt)
{
  var bytes = System.Text.Encoding.UTF8.GetBytes(input + salt);
  var sha256 = SHA256.Create();
  var hash = sha256.ComputeHash(bytes);

  return ByteArrayToString(hash);
}

盐世代

private static string GenerateSalt(int size)
{
  var rng = RandomNumberGenerator.Create();
  var buff = new byte[size];
  rng.GetBytes(buff);
  return Convert.ToBase64String(buff);
}



private static string ByteArrayToString(byte[] ba)
{
  var hex = new StringBuilder(ba.Length * 2);
  foreach (byte b in ba)
    hex.AppendFormat("{0:x2}", b);
  return hex.ToString();
}

谢谢,J

编辑1

这是我到目前为止所拥有的:

This is what I have so far:

    [Fact]
        public async void CreateUser_True()
        {
          //arrange
          var dataSource = new Mock<IRepository<User, int>>();
          var userResolverService = new Mock<IUserResolverService>();
          var tokenService = new Mock<ITokenService>();

      var users = new List<User>();
      users.Add(new User()
      {
        Email = "test@test.com",
        CustomerId = 1
      });
      dataSource.Setup(m => m.GetAllAsync()).ReturnsAsync(users); // Error Here with converting async task to IEnumerable...

          var accountService = new AccountService(dataSource.Object,userResolverService.Object,tokenService.Object);


          //act


          //assert


        }

主要问题是我不知道如何模拟,设置私有方法"CheckUserExists"的行为,因为它正在调用为类模拟的IRepository,因此在这种情况下,这将从我的私有方法返回我的GetAllAsync的模拟设置方法?

Main problem is that I have no idea how to Mock, set up behavior of private Method "CheckUserExists", as it's calling IRepository which is mocked for class, so will this in this case return my mock setup for GetAllAsync from this private method?

编辑2

public async Task<TEntity> AddAsync(TEntity entity)
{
  if (entity == null)
  {
    throw new ArgumentNullException(nameof(entity));
  }
  _entities.Add(entity);
  await _context.SaveChangesAsync();
  return entity;
}

编辑3

[Fact]
public async void CreateUser_True()
{
  //arrange
  var users = new List<User>();
  users.Add(new User()
  {
    Email = "test@test.com",
    CustomerId = 1
  });
  _dataSource.Setup(m => m.GetAllAsync()).ReturnsAsync(users);
  _dataSource.Setup(m => m.AddAsync(It.IsAny<User>())).Returns<User>(Task.FromResult);
  var accountService = new AccountService(_dataSource.Object, _userResolverService.Object, _tokenService.Object);


  //act
  var result = await accountService.CreateUser(new UserDTO()
  {
    Email = "truetest@test.com"
  });

  var updatedUsersList = await _dataSource.Object.GetAllAsync();
  var usersCount = updatedUsersList.Count();

  //assert
  Assert.True(result);
  Assert.Equal(2, usersCount);

}

推荐答案

由于要测试的方法是异步的,因此您需要设置所有异步依赖项以使方法流完成.至于私有方法,您想设置该方法中使用的任何依赖项的行为,在本例中为用户存储库.

As the method being tested is async you need to setup all async dependencies to allow the method flow to completion. As for the private method, you want to setup the behavior of any dependencies that are used within that method, which in this case is the users repository.

[Fact]
public async Task CreateUser_True() {
    //arrange
    var usersRepository = new Mock<IRepository<User, int>>();
    var userResolverService = new Mock<IUserResolverService>();
    var tokenService = new Mock<ITokenService>();

    var user = new User() {
        Email = "test@test.com",
        CustomerId = 1
    };
    var users = new List<User>() { user };

    usersRepository.Setup(_ => _.GetAllAsync()).ReturnsAsync(users);
    usersRepository.Setup(_ => _.AddAsync(It.IsAny<User>()))
        .Returns<User>(arg => Task.FromResult(arg)) //<-- returning the input value from task.
        .Callback<User>(arg => users.Add(arg)); //<-- use call back to perform function
    userResolverService.Setup(_ => _.GetCustomerId()).Returns(2);
    var accountService = new AccountService(usersRepository.Object, userResolverService.Object, tokenService.Object);

    //act
    var actual = await accountService.CreateUser(new UserDto { 
        Email = "email@example.com",
        Password = "monkey123",
        //...other code removed for brevity
    });

    //assert
    Assert.IsTrue(actual);
    Assert.IsTrue(users.Count == 2);
    Assert.IsTrue(users.Any(u => u.CustomerId == 2);
}

Moq快速入门上阅读以更好地了解如何使用模拟框架.

Read up on Moq Quickstart to get a better understanding of how to use the mocking framework.

这篇关于Moq的Xunit和Mock数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆