在测试中创建UserManager <t>的实例

时间:2019-02-28 08:39:53

标签: c# testing asp.net-core asp.net-core-mvc asp.net-core-identity

我对模拟的概念还很陌生,并且在向测试中注入/模拟UserManager<T>时感到很困难

我需要使用await _userManager.CreateAsync(user, password);

我找到了这个

public static UserManager<TUser> TestUserManager<TUser>(IUserStore<TUser> store = null) where TUser : class
{
    store = store ?? new Mock<IUserStore<TUser>>().Object;
    var options = new Mock<IOptions<IdentityOptions>>();
    var idOptions = new IdentityOptions();
    idOptions.Lockout.AllowedForNewUsers = false;
    options.Setup(o => o.Value).Returns(idOptions);
    var userValidators = new List<IUserValidator<TUser>>();
    var validator = new Mock<IUserValidator<TUser>>();
    userValidators.Add(validator.Object);
    var pwdValidators = new List<PasswordValidator<TUser>>();
    pwdValidators.Add(new PasswordValidator<TUser>());
    var userManager = new UserManager<TUser>(store, options.Object, new PasswordHasher<TUser>(),
        userValidators, pwdValidators, new UpperInvariantLookupNormalizer(),
        new IdentityErrorDescriber(), null,
        new Mock<ILogger<UserManager<TUser>>>().Object);
    validator.Setup(v => v.ValidateAsync(userManager, It.IsAny<TUser>()))
        .Returns(Task.FromResult(IdentityResult.Success)).Verifiable();

    return userManager;
}

但这会引发

  

System.NotSupportedException:存储未实现IUserPasswordStore。

如何在测试中创建有效的UserManager<T>实例?

我正在使用Xunit

1 个答案:

答案 0 :(得分:1)

首先,对您的方法进行修订,我读了一些不同的文章,人们说您不需要测试库和已经测试过的工具。 但是有时我们需要模拟UserManager来注入我们的服务并解决这些依赖关系。 UserManager的模拟非常简单,但是并没有很好地解释类似的错误消息。 我们必须首先模拟UserStore并将其提供给UserManager,要模拟UserStore,您可以创建派生MockUserStoreIUserStore的类IUserPasswordStore

public class MockUserStore : IUserStore<TUser>, IUserPasswordStore<TUser>

该模拟类必须实现IUserPasswordStore的某些方法,否则您将捕获该错误消息!

public Task SetPasswordHashAsync(TUser user, string passwordHash,
     CancellationToken cancellationToken)
{
    user.PasswordHash = passwordHash;
    return Task.FromResult(0);
}

public Task<string> GetPasswordHashAsync(TUser user, CancellationToken cancellationToken)
{
    return Task.FromResult<string>(user.PasswordHash);
}

public Task<bool> HasPasswordAsync(TUser user, CancellationToken cancellationToken)
{
    return Task.FromResult<bool>(!String.IsNullOrEmpty(user.PasswordHash));
}

您还可以使用类来模拟UserManager并使用模拟方法覆盖其方法:

public class MockUserManager : UserManager<TUser>
{
    public MockUserManager(IUserStore<TUser> store, IOptions<IdentityOptions> optionsAccessor,
     IPasswordHasher<TUser> passwordHasher, IEnumerable<IUserValidator<TUser>> userValidators,
      IEnumerable<IPasswordValidator<TUser>> passwordValidators, ILookupNormalizer keyNormalizer,
       IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<TUser>> logger)
        : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
    {
    }

    public override Task<IdentityResult> CreateAsync(TUser user)
    {
        return Task.FromResult(IdentityResult.Success);
    }
}

毕竟,您可以通过传递模拟的UserManager来模拟UserStore

    var userStore = new MockUserStore();
    var userManager = new MockUserManager(userStore,
                        new Mock<IOptions<IdentityOptions>>().Object,
                        new Mock<IPasswordHasher<AppUser>>().Object,
                        new IUserValidator<TUser>[0],
                        new IPasswordValidator<TUser>[0],
                        new Mock<ILookupNormalizer>().Object,
                        new Mock<IdentityErrorDescriber>().Object,
                        new Mock<IServiceProvider>().Object,
                        new Mock<ILogger<UserManager<TUser>>>().Object);
    return userManager;