title: Mocked UserManager doesn't really work as expected in tests
body: <p>I have some service that's responsible for changing user password while using <code>UserManager</code> and everything works fine, but when I want to write some tests, then it starts failing at method <code>CheckPassword</code>, which basically checks if <code>current (old password)</code> is correct</p>
  
  <pre><code>myService:
  public async bool TryChangePassword(User user, string OldPassword, string NewPassword)
  {
      (...)
  
      // it returns false
      var checkOldPassword = await _userManager.CheckPasswordAsync(user, OldPassword);
  
      if (!checkOldPassword)
      {
          return false;
      }
  
      var token = await _userManager.GeneratePasswordResetTokenAsync(user);
  
      var result = await _userManager.ResetPasswordAsync(user, token, NewPassword);
  
      return result.Succeeded;
  }
  
  myTests:
  
  private readonly UserManager&lt;User&gt; _userManager;
  
  [Fact]
  public void password_change_attempt_1()
  {
      var service = new myService(_context, _userManager);
  
      var user = new User("john");
  
      var register = _userManager.CreateAsync(user, "123456");
  
      _context.SaveChanges();
  
      Assert.True(_context.Users.Any());
  
      var result = service.TryChangePassword(user, "123456", "newPassword");
  }
  </code></pre>
  
  <p>but for some reason it fails at:</p>
  
  <blockquote>
    <p>var checkOldPassword = await _userManager.CheckPasswordAsync(user, OldPassword);</p>
  </blockquote>
  
  <p>it returns false, but as you can see, provided password is correct, probably there's something wrong with mocking user manager</p>
  
  <p>Here's how do I create mock of <code>UserManager</code> in <code>Tests'</code> constructor</p>
  
  <pre><code>public Tests()
  {
      var o = new DbContextOptionsBuilder&lt;Context&gt;();
      o.UseInMemoryDatabase(Guid.NewGuid().ToString());
      _context = new Context(o.Options);
      _context.Database.EnsureCreated();
  
      var userStore = new MockUserStore(_context);
      _userManager = new MockUserManager(userStore,
                          new Mock&lt;IOptions&lt;IdentityOptions&gt;&gt;().Object,
                          new Mock&lt;IPasswordHasher&lt;User&gt;&gt;().Object,
                          new IUserValidator&lt;User&gt;[0],
                          new IPasswordValidator&lt;User&gt;[0],
                          new Mock&lt;ILookupNormalizer&gt;().Object,
                          new Mock&lt;IdentityErrorDescriber&gt;().Object,
                          new Mock&lt;IServiceProvider&gt;().Object,
                          new Mock&lt;ILogger&lt;UserManager&lt;User&gt;&gt;&gt;().Object);
  }
  
  public class MockUserManager : UserManager&lt;User&gt;
  {
      public MockUserManager(IUserStore&lt;User&gt; store, IOptions&lt;IdentityOptions&gt; optionsAccessor,
       IPasswordHasher&lt;User&gt; passwordHasher, IEnumerable&lt;IUserValidator&lt;User&gt;&gt; userValidators,
        IEnumerable&lt;IPasswordValidator&lt;User&gt;&gt; passwordValidators, ILookupNormalizer keyNormalizer,
         IdentityErrorDescriber errors, IServiceProvider services, ILogger&lt;UserManager&lt;User&gt;&gt; logger)
          : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
      {
      }
  
      public override Task&lt;IdentityResult&gt; CreateAsync(User user)
      {
          this.Store.CreateAsync(user, new CancellationToken());
          return Task.FromResult(IdentityResult.Success);
      }
  }
  public class MockUserStore : IUserStore&lt;User&gt;, IUserPasswordStore&lt;User&gt;
  {
      public readonly Context _ctx;
  
      public MockUserStore(Context ctx)
      {
          _ctx = ctx;
      }
      public Task&lt;IdentityResult&gt; CreateAsync(User user, CancellationToken cancellationToken)
      {
          _ctx.Users.Add(user);
  
          return Task.FromResult(IdentityResult.Success);
      }
  
      public Task&lt;IdentityResult&gt; DeleteAsync(User user, CancellationToken cancellationToken)
      {
          throw new NotImplementedException();
      }
  
      public void Dispose()
      {
          throw new NotImplementedException();
      }
  
      public Task&lt;User&gt; FindByIdAsync(string userId, CancellationToken cancellationToken)
      {
          throw new NotImplementedException();
      }
  
      public Task&lt;User&gt; FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
      {
          throw new NotImplementedException();
      }
  
      public Task&lt;string&gt; GetNormalizedUserNameAsync(User user, CancellationToken cancellationToken)
      {
          throw new NotImplementedException();
      }
  
      public Task&lt;string&gt; GetPasswordHashAsync(User user, CancellationToken cancellationToken)
      {
          return Task.FromResult&lt;string&gt;(user.PasswordHash);
      }
  
      public Task&lt;string&gt; GetUserIdAsync(User user, CancellationToken cancellationToken)
      {
          return Task.FromResult&lt;string&gt;(user.Id);
      }
  
      public Task&lt;string&gt; GetUserNameAsync(User user, CancellationToken cancellationToken)
      {
          throw new NotImplementedException();
      }
  
      public Task&lt;bool&gt; HasPasswordAsync(User user, CancellationToken cancellationToken)
      {
          return Task.FromResult&lt;bool&gt;(!String.IsNullOrEmpty(user.PasswordHash));
      }
  
      public Task SetNormalizedUserNameAsync(User user, string normalizedName, CancellationToken cancellationToken)
      {
          throw new NotImplementedException();
      }
  
      public Task SetPasswordHashAsync(User user, string passwordHash, CancellationToken cancellationToken)
      {
          user.PasswordHash = passwordHash;
          return Task.FromResult(0);
      }
  
      public Task SetUserNameAsync(User user, string userName, CancellationToken cancellationToken)
      {
          throw new NotImplementedException();
      }
  
      public Task&lt;IdentityResult&gt; UpdateAsync(User user, CancellationToken cancellationToken)
      {
          throw new NotImplementedException();
      }
  }
  </code></pre>
  
  <p>I suppose it can be fixed here:</p>
  
  <pre><code>public Task&lt;IdentityResult&gt; CreateAsync(User user, CancellationToken cancellationToken)
  {
      _ctx.Users.Add(user);
  
      return Task.FromResult(IdentityResult.Success);
  }
  </code></pre>
  
  <p>by adding something like</p>
  
  <pre><code>user.PasswordHash = generateHash(password)
  </code></pre>
  
  <p>but how can I know how many iterations do ASP.NET Core Identity does use?</p>
  
  <p><a href="https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/consumer-apis/password-hashing?view=aspnetcore-2.2" rel="nofollow noreferrer">https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/consumer-apis/password-hashing?view=aspnetcore-2.2</a></p>
  
  <pre><code>string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
      password: password,
      salt: salt,
      prf: KeyDerivationPrf.HMACSHA1,
      iterationCount: 10000,
      numBytesRequested: 256 / 8));
  </code></pre>