Interfaces for mocking ConfirmEmailAsync and other UserManager methods in MVC5

前端 未结 2 444
被撕碎了的回忆
被撕碎了的回忆 2021-01-20 16:45

I am trying to unit test this controller method, which comes out of the box in current MVC projects.

[AllowAnonymous]
public async Task C         


        
2条回答
  •  感动是毒
    2021-01-20 16:56

    ConfirmEmailAsync is not currently part of an interface in the framework. It's in the UserManager class which is the base class of Identity framework.

    My solution?

    Abstract all the things

    I got around this by abstracting most of the functionality of identity into its own project so that I can unit test it easier and reuse the abstraction in other projects. I got the idea after reading this article

    Persistence-Ignorant ASP.NET Identity with Patterns

    I then fine tuned the idea to suit my needs. I basically just swapped everything i needed from asp.net.identity for my custom interfaces which more or less mirrored the functionality provided by the framework but with the advantage of easier mockability.

    IIdentityUser

    /// 
    ///  Minimal interface for a user with an id of type 
    /// 
    public interface IIdentityUser : IIdentityUser { }
    /// 
    ///  Minimal interface for a user
    /// 
    public interface IIdentityUser
        where TKey : System.IEquatable {
    
        TKey Id { get; set; }
        string UserName { get; set; }
        string Email { get; set; }
        bool EmailConfirmed { get; set; }
        string EmailConfirmationToken { get; set; }
        string ResetPasswordToken { get; set; }
        string PasswordHash { get; set; }
    }
    

    IIdentityManager

    /// 
    /// Exposes user related api which will automatically save changes to the UserStore
    /// 
    public interface IIdentityManager : IIdentityManager { }
    /// 
    /// Exposes user related api which will automatically save changes to the UserStore
    /// 
    public interface IIdentityManager : IIdentityManager
        where TUser : class, IIdentityUser { }
    /// 
    /// Exposes user related api which will automatically save changes to the UserStore
    /// 
    public interface IIdentityManager : IDisposable
        where TUser : class, IIdentityUser
        where TKey : System.IEquatable {
    
        Task AddPasswordAsync(TKey userid, string password);
        Task ChangePasswordAsync(TKey userid, string currentPassword, string newPassword);
        Task ConfirmEmailAsync(TKey userId, string token);
        //...other code removed for brevity
    }
    

    IIdentityResult

    /// 
    /// Represents the minimal result of an identity operation
    /// 
    public interface IIdentityResult : System.Collections.Generic.IEnumerable {
        bool Succeeded { get; }
    }
    

    In my default implementation of the identity manager i simply wrapped the ApplicationManager and then mapped results and functionality between my types and the asp.net.identity types.

    public class DefaultUserManager : IIdentityManager {
        private ApplicationUserManager innerManager;
    
        public DefaultUserManager() {
            this.innerManager = ApplicationUserManager.Instance;
        }
        //..other code removed for brevity
        public async Task ConfirmEmailAsync(string userId, string token) {
            var result = await innerManager.ConfirmEmailAsync(userId, token);
            return result.AsIIdentityResult();
        }
        //...other code removed for brevity
    }
    

提交回复
热议问题