我正在使用 Moq 创建单元测试,以实现由 Microsoft Scaffold Identity 自动生成的类的 100% 覆盖率,具体来说Register.cs.cshtml
。但是,我在某些测试中遇到了此错误:
System.NotSupportedException :默认 UI 需要具有电子邮件支持的用户存储
以下是
- 日志错误,
- 我如何设置模拟测试,
- 我如何配置 Microsoft Identity 属性(
Program.cs
), - 的参数
RegisterModel
,这是我需要测试的类, GetEmailStore()
发生错误的方法。
日志错误:
错误信息:
System.NotSupportedException:默认 UI 需要具有电子邮件支持的用户存储。
堆栈跟踪:
位于 /home/ygorgsena/eam/Main/Areas/Identity/Pages/Account/Register.cshtml.cs:line 219
中的 EAM.Areas.Identity.Pages.Account.RegisterModel..ctor(SignInManager`1 signInManager, UserManager`1 userManager, IUserStore`1 userStore, ILogger`1 logger, IEmailSender emailSender) 位于 /home/ygorgsena/eam/Main/Areas/Identity/Pages/Account/Register.cshtml.cs:line 44
中的 EAM.Tests.Unit.RegisterUnitTest..ctor() 位于 /home/ygorgsena/eam/Tests/Unit/RegisterUnitTest.cs:line 91
中System.RuntimeType.CreateInstanceDefaultCtor(布尔publicOnly,布尔wrapExceptions)
我如何设置模拟:
public class RegisterModelTests
{
private readonly Mock<UserManager<IdentityUser>> _userManagerMock;
private readonly Mock<SignInManager<IdentityUser>> _signInManagerMock;
private readonly Mock<IUserStore<IdentityUser>> _userStoreMock;
private readonly Mock<IUserEmailStore<IdentityUser>> _emailStoreMock;
private readonly Mock<ILogger<RegisterModel>> _loggerMock;
private readonly Mock<IEmailSender> _emailSenderMock;
private readonly RegisterModel _pageModel;
public RegisterModelTests()
{
_userStoreMock = new Mock<IUserStore<IdentityUser>>();
_userManagerMock = new Mock<UserManager<IdentityUser>>(
_userStoreMock.Object,
new Mock<IOptions<IdentityOptions>>().Object,
new Mock<IPasswordHasher<IdentityUser>>().Object,
Array.Empty<IUserValidator<IdentityUser>>(),
Array.Empty<IPasswordValidator<IdentityUser>>(),
new Mock<ILookupNormalizer>().Object,
new Mock<IdentityErrorDescriber>().Object,
new Mock<IServiceProvider>().Object,
new Mock<ILogger<UserManager<IdentityUser>>>().Object);
_signInManagerMock = new Mock<SignInManager<IdentityUser>>(
_userManagerMock.Object,
new Mock<IHttpContextAccessor>().Object,
new Mock<IUserClaimsPrincipalFactory<IdentityUser>>().Object,
new Mock<IOptions<IdentityOptions>>().Object,
new Mock<ILogger<SignInManager<IdentityUser>>>().Object,
new Mock<IAuthenticationSchemeProvider>().Object,
new Mock<IUserConfirmation<IdentityUser>>().Object);
_emailStoreMock = _userStoreMock.As<IUserEmailStore<IdentityUser>>();
_loggerMock = new Mock<ILogger<RegisterModel>>();
_emailSenderMock = new Mock<IEmailSender>();
_pageModel = new RegisterModel(
_userManagerMock.Object, _userStoreMock.Object, _signInManagerMock.Object, _loggerMock.Object, _emailSenderMock.Object);
}
[Fact]
public void GetEmailStore_ThrowsNotSupportedException_WhenUserManagerDoesNotSupportEmail()
{
// Arrange
_ = _userManagerMock.Setup(m => m.SupportsUserEmail).Returns(false);
// Use reflection to access the private GetEmailStore method
MethodInfo? methodInfo = typeof(RegisterModel).GetMethod("GetEmailStore", BindingFlags.NonPublic | BindingFlags.Instance);
// Act & Assert
Assert.NotNull(methodInfo);
_ = Assert.Throws<NotSupportedException>(() => methodInfo.Invoke(_pageModel, null));
}
我如何在以下位置配置 Microsoft Identity 属性Program.cs
:
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true).AddEntityFrameworkStores<EAMContext>();
该类的参数RegisterModel
:
public class RegisterModel : PageModel
{
private readonly SignInManager<IdentityUser> _signInManager;
private readonly UserManager<IdentityUser> _userManager;
private readonly IUserStore<IdentityUser> _userStore;
private readonly IUserEmailStore<IdentityUser> _emailStore;
private readonly ILogger<RegisterModel> _logger;
private readonly IEmailSender _emailSender;
public RegisterModel(
UserManager<IdentityUser> userManager,
IUserStore<IdentityUser> userStore,
SignInManager<IdentityUser> signInManager,
ILogger<RegisterModel> logger,
IEmailSender emailSender)
{
_userManager = userManager;
_userStore = userStore;
_emailStore = GetEmailStore();
_signInManager = signInManager;
_logger = logger;
_emailSender = emailSender;
}
我尝试查看源代码以了解其工作原理IUserEmailStore<TUser>
。代码位于此链接。此GetEmailStore()
方法就是发生错误的地方。
private IUserEmailStore<TUser> GetEmailStore()
{
if (Store is not IUserEmailStore<TUser> emailStore)
{
throw new NotSupportedException(Resources.StoreNotIUserEmailStore);
}
return emailStore;
}
该Store
字段在第 139 行定义,其类型为
protected internal IUserStore<TUser> Store { get; set; }
该GetEmailStore()
方法访问类型的属性IUserStore
并检查是否IUserEmailStore
存在。
正如您在“如何设置模拟”部分中所看到的,我尝试IUserStore
先模拟,然后模拟IUserEmailStore
,但似乎不起作用。
尽管我多次尝试解决这个问题,但仍然遇到问题。我非常感谢任何有关正确配置模拟以包含电子邮件支持进行测试的帮助或见解。谢谢!
回答我自己的问题,以防将来其他人遇到同样的问题:
在提供的代码中,即使我们在模拟时将 扩展到
IUserStore
,IEmailUserStore
我们仍然需要在将其作为参数传递给 之前DefaultUI
手动设置启用电子邮件支持的布尔值:_userManagerMock
_signInManager