C# 嘲笑签名管理员
使用Moq和xUnit进行单元测试的新手。我试图模拟控制器构造函数中用于构建单元测试的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
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();