C# 嘲笑签名管理员

C# 嘲笑签名管理员,c#,asp.net,unit-testing,asp.net-core,moq,C#,Asp.net,Unit Testing,Asp.net Core,Moq,使用Moq和xUnit进行单元测试的新手。我试图模拟控制器构造函数中用于构建单元测试的SignInManager。我可以找到的SignInManager构造函数的文档说明它接受UserManager和AuthenticationManager对象:`2 当我试图模拟控制器时,我得到一个错误,它说它无法实例化SignInManager和AuthenticationManager类的代理 错误: “信息: Castle.DynamicProxy.InvalidProxyConstructor Arg

使用Moq和xUnit进行单元测试的新手。我试图模拟控制器构造函数中用于构建单元测试的
SignInManager
。我可以找到的
SignInManager
构造函数的文档说明它接受
UserManager
AuthenticationManager
对象:`2

当我试图模拟控制器时,我得到一个错误,它说它无法实例化
SignInManager
AuthenticationManager
类的代理

错误:

“信息: Castle.DynamicProxy.InvalidProxyConstructor Arguments异常:Can 未实例化类的代理: Microsoft.AspNetCore.Identity.SignInManager[[Models.AppUser, ,版本=1.0.0.0,区域性=中性, 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());
}
public void可以发送密码重置电子邮件()
{
//安排
//创建模拟服务
Mock mockEmailService=new Mock();
Mock mockRepo=新Mock();
Mock mockUsrMgr=GetMockUserManager();
var mockSignInMgr=GetMockSignInManager();
Mock mockUsrVal=new Mock();
Mock mockPwdVal=新Mock();
Mock mockPwdHshr=新Mock();
模拟模型=新模拟();
model.Object.Email=”joe@example.com";
var user=new-AppUser();
var token=mockUsrMgr.Object.GeneratePasswordResetTokenAsync(用户).Result;
//创建控制器消息所需的模拟临时数据
Mock tempData=new Mock();
//创建控制器
//这行有错误
AccountController控制器=新的AccountController(mockUsrMgr.Object、mockSignInMgr.Object、mockUsrVal.Object、mockPwdVal.Object、mockPwdHshr.Object、mockEmailService.Object)
{
TempData=TempData.Object
};
//表演
//控制器应调用电子邮件操作方法
controller.PasswordResetEmail(model.Object);
//断言
//验证电子邮件服务方法是否调用过一次
验证(m=>m.PasswordResetMessage(用户,“测试电子邮件”),Times.Once();
}
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);
}
//创建一个模拟SignInManager类
私有模拟GetMockSignInManager()
{
var mockUsrMgr=GetMockUserManager();
var mockAuthMgr=new Mock();
返回新的Mock(mockUsrMgr.Object、mockAuthMgr.Object);
}

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

您正在查看的文档是供参考的

如果查看错误消息,您将看到Moq实际上正在尝试创建Microsoft.AspNetCore.Identity.SignInManager类型的对象。请注意
AspNet
AspNetCore
之间的差异

基本上,您看到的是经典ASP.NET基于Owin的旧标识堆栈中使用的
SignInManager
。但是您需要查看ASP.NET核心版本。如果您查看该类型的文档,您将看到:

公共签名管理器(
用户管理器用户管理器,
IHttpContextAccessor上下文访问器,
IUSERclaimsprincipal工厂索赔工厂,
IOPS选项访问器,
ILogger记录器,
IAAuthenticationSchemeProvider方案);

我就是这样做的,希望这对您有所帮助

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

    }
公共类FakeSignInManager:SignInManager
{
公共伪造签名管理器()
:base(新的FakeUserManager(),
新建Mock().Object,
新建Mock().Object,
新建Mock().Object,
新建Mock().Object,
新建Mock().Object)
{ }        
}
公共类FakeUserManager:UserManager
{
公共FakeUserManager()
:base(新的Mock().Object,
新建Mock().Object,
新建Mock().Object,
新的IUserValidator[0],
新的IPasswordValidator[0],
新建Mock().Object,
新建Mock().Object,
新建Mock().Object,
新建Mock().Object)
{ }
公共覆盖任务CreateAync(ApplicationUser用户,字符串密码)
{
返回Task.FromResult(IdentityResult.Success);
}
公共覆盖任务AddToRoleAsync(ApplicationUser用户,字符串角色)
{
返回Task.FromResult(IdentityResult.Success);
}
公共覆盖任务GenerateEmailConfirmationTokenAsync(ApplicationUser用户)
{
返回Task.FromResult(Guid.NewGuid().ToString());
}
}

SignInManager没有不带参数的构造函数,因此您必须在
新模拟(**这里的参数**)中传递参数。

其中一些参数不能为null,因此必须对其进行模拟,如:

  • UserManager
    =>第一个参数
  • IHttpContextAccessor
    =>第二个参数
  • 这里的问题是,甚至
    UserManager
    都没有无参数的构造函数,因此必须使用其参数进行模拟

    对于
    Usermanager
    不应为null的参数
    IUserStore
    ==>第一个参数

    这里我是如何使用最小代码的

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

    var\u mockUserManager=new Mock

    对于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);
    
    var userManagerMock=new Mock(
    /*IUserStore store*/Mock.Of(),
    /*IOptions选项访问器*/null,
    /*IPasswordHasher密码hasher*/null,
    /*IEnumerable userValidators*/null,
    /*IEnumerable passwordvalidator*/null,
    /*ILookupNormalizer键规范化器*/null,
    /*IdentityErrorDescriber错误*/null,
    /*IServiceProvider服务*/null,
    /*i记录器*/null);
    var signnmanagermock=新模拟(
    userManagerMock.Object,
    /*IHttpContextAccessor contextAccessor*/Mock.Of(),
    /*IUSERclaimsprincipalfact
    
    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);
    
    var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(Enumerable.Empty<Claim>()));
    var signInManager = A.Fake<SignInManager<User>>();
    A.CallTo(() => signInManager.IsSignedIn(claimsPrincipal)).Returns(false);
    ...
    A.CallTo(() => _signInManager.SignOutAsync()).MustHaveHappened();