首页 > 解决方案 > 测试用户管理器创建用户但密码哈希属性为空

问题描述

我正在使用 Microsoft.AspNetCore.Identity.UserManager 并试图模拟新用户的创建。事实上,它确实使用用户名、电子邮件等创建了一个新用户,但密码哈希属性仍然为空。

这就是我如何通过一些额外的设置来设置模拟用户管理器:

        var store = new Mock<IUserPasswordStore<User>>();

        var validator = new UserValidator<User>();
        var passValidator = new PasswordValidator<User>();

        var mgr = new Mock<UserManager<User>>(store.Object, null, null, null, null, null, null, null, null);
        mgr.Object.UserValidators.Add(validator);
        mgr.Object.PasswordValidators.Add(passValidator);
        mgr.Object.PasswordHasher = new PasswordHasher<User>();
        mgr.Object.Options = AuthenticationRules.DefaultAuthenticationRules();

        List<User> users= new List<User>();

        mgr.Setup(x => x.DeleteAsync(It.IsAny<User>())).ReturnsAsync(IdentityResult.Success);
        mgr.Setup(x => x.CreateAsync(It.IsAny<User>(), It.IsAny<string>())).ReturnsAsync(IdentityResult.Success).Callback<User, string>((x, y) => users.Add(x));
        mgr.Setup(x => x.UpdateAsync(It.IsAny<User>())).ReturnsAsync(IdentityResult.Success);

'DefaultAuthenticationRules' 返回:

    public static IdentityOptions DefaultAuthenticationRules(IdentityOptions identityOptions = null)
    {
        if(identityOptions == null)
            identityOptions = new IdentityOptions();

        identityOptions.User.RequireUniqueEmail = true;
        identityOptions.Password.RequireNonAlphanumeric = false;
        identityOptions.Password.RequiredUniqueChars = 0;

        return identityOptions;
    }

然后,我将 mgr.Object 传递给处理创建新用户的方法,其中“对象”为 _userManager

        var creationResult = await _userManager.CreateAsync(_user, _registrationModel.Password);

        if (!creationResult.Succeeded)
            return false;

        return true;

_registrationModel.Password 已填充。

所以现在当设置在回调中添加一个新用户到用户列表时,用户会在没有密码哈希的情况下填充。我不确定我在这里缺少什么。我在 mgr.Setup 中遗漏了一些东西?

提前致谢

标签: c#unit-testing.net-coreasp.net-identitymoq

解决方案


您的回调函数Callback<User, string>((x, y) => users.Add(x));将在测试完成后执行,它将接受您传递给模拟方法的相同参数值作为参数,在您的情况下,密码可能是空字符串或 null。

_registrationModel.Password 已填充。

好的,但是生成一些密码的内部代码对参数没有任何影响(x,y) => {..}

请参阅此代码(从this great answer复制):

public interface IFoo
{
    int Bar(bool b);
}

var mock = new Mock<IFoo>();

mock.Setup(mc => mc.Bar(It.IsAny<bool>()))
    .Callback<bool>(b => Console.WriteLine("Bar called with: " + b))
    .Returns(99999);

var ret1 = mock.Object.Bar(true);
Console.WriteLine("Result ret1: " + ret1);
var ret2 = mock.Object.Bar(false);
Console.WriteLine("Result ret2: " + ret2);

//OUTPUT:
//Result ret1: true.
//Result ret1: false.

在示例中,无论方法内部发生什么Bar,输出都将仅取决于模拟函数的调用参数值。


推荐阅读