如何模拟 Asp.net 标识 UserManager 的 CreateAsync 方法

How to mock Asp.net identity UserManager's CreateAsync method

我正在尝试模拟 UserStore 的 CreateAsync 方法来拥有内存中的用户存储。

public void Can_Create_User()
{
    //Arrange
    var dummyUser = new ApplicationUser() { UserName = "PinkWarrior", Email = "PinkWarrior@PinkWarrior.com" };
    var mockStore = new Mock<IUserStore<ApplicationUser>>();

    var userManager = new UserManager<ApplicationUser>(mockStore.Object);
    mockStore.Setup(x => x.CreateAsync(dummyUser))
                .Returns(Task.FromResult(IdentityResult.Success));


    //Act
    Task<IdentityResult> tt = (Task<IdentityResult>)mockStore.Object.CreateAsync(dummyUser);
    var user = userManager.FindByName("PinkWarrior");

    //Assert
    Assert.AreEqual("PinkWarrior", user.UserName);
}

上面的 user 总是空的,因为我从不插入它。所以我遇到的问题是 我怎样才能让 userManager 不是一个模拟 return 我的模拟商店的用户?

This answer 有点相似,但没有在这里回答我的问题。

非常感谢任何帮助

您的模拟用户存储未正确准备。因为它是一个模拟,所以你不应该期望 mockStore.Object.CreateAsync 会做任何事情,即它不会在任何地方添加任何东西。

您需要准备相应的"read"操作,因为用户管理器很可能会调用它。 (将模拟的 FindByNameAsync 方法设置为 return 您需要的标识)。

在任何情况下,您尝试做的事情都是毫无意义的,因为您正在尝试测试框架 class UserManager。

可能您真正需要的是模拟用户管理器本身,并在您的控制器中或在您使用该用户管理器的任何地方使用该模拟。

您需要模拟对 FindByNameAsync 的调用,因为这是 UserManager 将调用的内容:

public void Can_Create_User()
{
    //Arrange
    var dummyUser = new ApplicationUser() { UserName = "PinkWarrior", Email = "PinkWarrior@PinkWarrior.com" };
    var mockStore = new Mock<IUserStore<ApplicationUser>>();

    var userManager = new UserManager<ApplicationUser>(mockStore.Object);
    mockStore.Setup(x => x.CreateAsync(dummyUser))
                .Returns(Task.FromResult(IdentityResult.Success));

    mockStore.Setup(x => x.FindByNameAsync(dummyUser.UserName))
                .Returns(Task.FromResult(dummyUser));


    //Act
    Task<IdentityResult> tt = (Task<IdentityResult>)mockStore.Object.CreateAsync(dummyUser);
    var user = userManager.FindByName("PinkWarrior");

    //Assert
    Assert.AreEqual("PinkWarrior", user.UserName);
}

但是,我相信通过这样的测试,您正在测试 Microsoft.AspNet.Identity.UserManager 而不是您的代码。您要证明的是 UserManager 以某种方式调用了您的 mockStore。

Source code for Microsoft.AspNet.Identity 包含这些类型的测试。

检查 MockHelper.cs class 来自 Identity git 存储库

中的测试

Identity GitHub repo link or Closed Issue for mocking

你应该在那里找到关于模拟的灵感,例如

  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,
            null);
        validator.Setup(v => v.ValidateAsync(userManager, It.IsAny<TUser>()))
            .Returns(Task.FromResult(IdentityResult.Success)).Verifiable();
        return userManager;
    }

我用这个方法使用它:

       private UserController BuildCoontrollerWithDatabase()
    {
        DbContextOptionsBuilder dbContextOptionsBuilder = new DbContextOptionsBuilder();
        dbContextOptionsBuilder.UseInMemoryDatabase();

        ApplicationDbContext applicationDbContext = new ApplicationDbContext( dbContextOptionsBuilder.Options);

        var userStore = new UserStore<ApplicationUser>(applicationDbContext);

        UserManager<ApplicationUser>  userManager = TestUserManager<ApplicationUser>(userStore);

        return new UserController(userManager);


    }

这对我有用

    public void Can_Create_User()
    {
        //Arrange
        var dummyUser = new ApplicationUser() { UserName = "PinkWarrior", Email = "PinkWarrior@PinkWarrior.com" };
        var mockStore = new Mock<IUserStore<ApplicationUser>>();

        var userManager = new UserManager<ApplicationUser>(mockStore.Object, null, null, null, null, null, null, null, null);

        mockStore.Setup(s => s.CreateAsync(It.IsAny<ApplicationUser>(), CancellationToken.None))
            .Returns(Task.FromResult(IdentityResult.Success));

        mockStore.Setup(s => s.FindByNameAsync(It.IsAny<string>(), CancellationToken.None))
            .Returns(Task.FromResult(dummyUser)).Verifiable();

        //Act
        Task<IdentityResult> tt = (Task<IdentityResult>)mockStore.Object.CreateAsync(dummyUser,CancellationToken.None);
        var user = userManager.FindByNameAsync("PinkWarrior");
        user.Wait();

        //Assert
        Assert.True("PinkWarrior" == user.Result.UserName);
    }