模拟SignInManager

coo*_*and 5 c# asp.net unit-testing moq asp.net-core

使用Moq和xUnit进行单元测试的新手.我试图模拟一个SignInManager在控制器构造函数中使用的构建单元测试.我可以为SignInManager构造函数找到的文档说它接受一个UserManagerAuthenticationManager对象:https://msdn.microsoft.com/en-us/library/mt173769(v = vs.108).aspx #M:Microsoft.AspNet.Identity .Owin.SignInManager`2.

当我尝试模拟控制器时,我收到一个错误,说它无法实例化SignInManagerAuthenticationManager类的代理.

错误:

"消息:Castle.DynamicProxy.InvalidProxyConstructorArgumentsException:无法实例化类的代理:Microsoft.AspNetCore.Identity.SignInManager1 [[Models.AppUser ,, Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]].找不到与给定参数匹配的构造函数:Castle.Proxies.UserManager`1Proxy Castle.Proxies.AuthenticationManagerProxy"

单元测试:

public void Can_Send_Password_Reset_Email()
{
    //Arrange
    //create mock services
    Mock<IEmailService> mockEmailService = new Mock<IEmailService>();
    Mock<ILessonRepository> mockRepo = new Mock<ILessonRepository>();
    Mock<UserManager<AppUser>> mockUsrMgr = GetMockUserManager();
    var mockSignInMgr = GetMockSignInManager();
    Mock<UserValidator<AppUser>> mockUsrVal = new Mock<UserValidator<AppUser>>();
    Mock<PasswordValidator<AppUser>> mockPwdVal = new Mock<PasswordValidator<AppUser>>();
    Mock<PasswordHasher<AppUser>> mockPwdHshr = new Mock<PasswordHasher<AppUser>>();
    Mock<ForgotPasswordModel> model = new Mock<ForgotPasswordModel>();
    model.Object.Email = "joe@example.com";

    var user = new AppUser();
    var token = mockUsrMgr.Object.GeneratePasswordResetTokenAsync(user).Result;

    //create mock temporary data, needed for controller message
    Mock<ITempDataDictionary> tempData = new Mock<ITempDataDictionary>();
    //create the controller
    //ERROR ON THIS LINE
    AccountController controller = new AccountController(mockUsrMgr.Object, mockSignInMgr.Object, mockUsrVal.Object, mockPwdVal.Object, mockPwdHshr.Object, mockEmailService.Object)
    {
        TempData = tempData.Object
    };

    //Act
    //the controller should call the email action method
    controller.PasswordResetEmail(model.Object);

    //Assert
    //verify that the email service method was called one time
    mockEmailService.Verify(m => m.PasswordResetMessage(user, "Test Email"), Times.Once());
}
Run Code Online (Sandbox Code Playgroud)

SignInManager模拟函数:

//create a mock SignInManager class
private Mock<SignInManager<AppUser>> GetMockSignInManager()
{
    var mockUsrMgr = GetMockUserManager();
    var mockAuthMgr = new Mock<AuthenticationManager>();
    return new Mock<SignInManager<AppUser>>(mockUsrMgr.Object, mockAuthMgr.Object);
}
Run Code Online (Sandbox Code Playgroud)

GetMockUserManager()其他单元测试中的工作正常,似乎不是问题.

Den*_*uig 11

我就是这样做的,我希望这会对你有所帮助.

public class FakeSignInManager : SignInManager<ApplicationUser>
{
    public FakeSignInManager()
            : base(new FakeUserManager(),
                 new Mock<IHttpContextAccessor>().Object,
                 new Mock<IUserClaimsPrincipalFactory<ApplicationUser>>().Object,
                 new Mock<IOptions<IdentityOptions>>().Object,
                 new Mock<ILogger<SignInManager<ApplicationUser>>>().Object,
                 new Mock<IAuthenticationSchemeProvider>().Object)
        { }        
}



public class FakeUserManager : UserManager<ApplicationUser>
    {
        public FakeUserManager()
            : base(new Mock<IUserStore<ApplicationUser>>().Object,
              new Mock<IOptions<IdentityOptions>>().Object,
              new Mock<IPasswordHasher<ApplicationUser>>().Object,
              new IUserValidator<ApplicationUser>[0],
              new IPasswordValidator<ApplicationUser>[0],
              new Mock<ILookupNormalizer>().Object,
              new Mock<IdentityErrorDescriber>().Object,
              new Mock<IServiceProvider>().Object,
              new Mock<ILogger<UserManager<ApplicationUser>>>().Object)
        { }

        public override Task<IdentityResult> CreateAsync(ApplicationUser user, string password)
        {
            return Task.FromResult(IdentityResult.Success);
        }

        public override Task<IdentityResult> AddToRoleAsync(ApplicationUser user, string role)
        {
            return Task.FromResult(IdentityResult.Success);
        }

        public override Task<string> GenerateEmailConfirmationTokenAsync(ApplicationUser user)
        {
            return Task.FromResult(Guid.NewGuid().ToString());
        }

    }
Run Code Online (Sandbox Code Playgroud)


huy*_*itw 11

对于 ASP.NET Core 5,可以使用此设置:

var userManagerMock = new Mock<UserManager<User>>(
    /* IUserStore<TUser> store */Mock.Of<IUserStore<User>>(),
    /* IOptions<IdentityOptions> optionsAccessor */null,
    /* IPasswordHasher<TUser> passwordHasher */null,
    /* IEnumerable<IUserValidator<TUser>> userValidators */null,
    /* IEnumerable<IPasswordValidator<TUser>> passwordValidators */null,
    /* ILookupNormalizer keyNormalizer */null,
    /* IdentityErrorDescriber errors */null,
    /* IServiceProvider services */null,
    /* ILogger<UserManager<TUser>> logger */null);

var signInManagerMock = new Mock<SignInManager<User>>(
    userManagerMock.Object,
    /* IHttpContextAccessor contextAccessor */Mock.Of<IHttpContextAccessor>(),
    /* IUserClaimsPrincipalFactory<TUser> claimsFactory */Mock.Of<IUserClaimsPrincipalFactory<User>>(),
    /* IOptions<IdentityOptions> optionsAccessor */null,
    /* ILogger<SignInManager<TUser>> logger */null,
    /* IAuthenticationSchemeProvider schemes */null,
    /* IUserConfirmation<TUser> confirmation */null);
Run Code Online (Sandbox Code Playgroud)


Waj*_*khi 7

SignInManager拥有不带参数没有构造,所以你必须通过在参数new Mock<SignInManager>(**Params here**)

其中一些参数不能为空,因此它们也必须被模拟:

  1. UserManager<TUser> ==> 第一个参数。
  2. IHttpContextAccessor ==> 第二个参数。

这里的问题是甚至UserManager没有一个无参数的构造函数,所以你必须用它的参数来模拟

对于Usermanager不应该为空IUserStore<User>的参数 ==> 第一个参数

所以在这里我是如何用最少的代码做的

var _mockUserManager = new Mock<ApiUserManager>(new Mock<IUserStore<ApiUser>>().Object,
                null, null, null, null, null, null, null, null);
var _contextAccessor = new Mock<IHttpContextAccessor>();
var _userPrincipalFactory = new Mock<IUserClaimsPrincipalFactory<ApiUser>>();
Mock<ApiSignInManager>mockApiSignInManager = new Mock<ApiSignInManager>(_mockUserManager.Object,
               _contextAccessor.Object, _userPrincipalFactory.Object, null, null, null);
Run Code Online (Sandbox Code Playgroud)

此回复的灵感来自GitHub 论坛上umutesen


pok*_*oke 3

您正在查看的文档适用于Microsoft.AspNet.Identity.Owin.SignInManager.

如果您查看错误消息,您会发现 Moq 实际上正在尝试创建 类型的对象Microsoft.AspNetCore.Identity.SignInManagerAspNet注意和之间的区别AspNetCore

基本上,您正在查看SignInManager旧的基于 Owin 的经典 ASP.NET 身份堆栈中使用的身份堆栈。但你需要查看 ASP.NET Core 版本。如果您查看该类型的文档,您会发现构造函数还有更多依赖项

public SignInManager(
    UserManager<TUser> userManager,
    IHttpContextAccessor contextAccessor,
    IUserClaimsPrincipalFactory<TUser> claimsFactory,
    IOptions<Microsoft.AspNetCore.Identity.IdentityOptions> optionsAccessor,
    ILogger<Microsoft.AspNetCore.Identity.SignInManager<TUser>> logger,
    IAuthenticationSchemeProvider schemes);
Run Code Online (Sandbox Code Playgroud)