【问题标题】:How to mock Asp.net identity UserManager's CreateAsync method如何模拟 Asp.net 身份 UserManager 的 CreateAsync 方法
【发布时间】:2021-11-15 17:37:52
【问题描述】:

我正在尝试模拟 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,这不是一个模拟从我的模拟商店返回用户?

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

非常感谢任何帮助

【问题讨论】:

    标签: c# asp.net moq


    【解决方案1】:

    您需要模拟对 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 包含这些类型的测试。

    【讨论】:

    • 谢谢你,你的代码工作了,现在测试通过了,所以你得到了赏金:)耶。我确实明白测试 UserManager 毫无意义,但我最初打算模拟它而没有考虑太多。
    【解决方案2】:

    Identity git repo 中的测试中检查MockHelper.cs

    Identity GitHub repo linkClosed 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);
    
    
        }
    

    【讨论】:

      【解决方案3】:

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

      您需要准备相应的“读取”操作,因为用户管理器很可能会调用它。 (在 mock 上设置 FindByNameAsync 方法以返回您需要的身份)。

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

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

      【讨论】:

        【解决方案4】:

        这对我有用

            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);
            }
        

        【讨论】:

          猜你喜欢
          • 2020-08-13
          • 1970-01-01
          • 2020-11-29
          • 2020-10-29
          • 2016-03-26
          • 1970-01-01
          • 2016-07-31
          • 2017-09-01
          • 2015-09-13
          相关资源
          最近更新 更多