I am trying to simply test my Register.cshtml.cs OnGet()
method. The PageModel requires a UserManager<TUser>
and a SignInManager<TUser>
. I need to mock the SignInManager<TUser>.IsSignedIn(ClaimsPrincipal user)
method which requires those classes. The problem is the constructors for those classes in ASP .NET Core are much more complicated than most solutions document for previous ASP .NET versions. The only constructor for UserManager
has nine required parameters, and I believe SignInManager
required seven.
I was able to get far enough for my test to execute but the mocked method is not executing.
My test:
[Fact]
public void OnGet_UserIsSignedIn_RedirectsToIndex()
{
using (var testContext = new ApplicationDbContext(TestHelper.TestApplicationDbContextOptions()))
{
// Arrange
var mockUserStore = new Mock<IUserStore<AppUser>>();
var userManager = new UserManager<AppUser>(mockUserStore.Object, null, null, null, null, null, null, null, null);
var mockSignInManager = new Mock<SignInManager<AppUser>>(
userManager,
new HttpContextAccessor(),
new Mock<IUserClaimsPrincipalFactory<AppUser>>().Object,
new Mock<IOptions<IdentityOptions>>().Object,
new Mock<ILogger<SignInManager<AppUser>>>().Object,
new Mock<IAuthenticationSchemeProvider>().Object,
new Mock<IUserConfirmation<AppUser>>().Object
);
var claimsPrincipal = new TestPrincipal(new Claim("name", "John Doe"));
var _mockConfig = new Mock<IConfiguration>();
var _mockUserValidator = new UserValidator<AppUser>();
var _mockLogger = new Mock<ILogger<RegisterModel>>();
var _mockEmailSender = new Mock<IEmailSender>();
var registerModel = new RegisterModel(_mockConfig.Object, userManager, mockSignInManager.Object, _mockUserValidator, _mockLogger.Object, _mockEmailSender.Object);
mockSignInManager.Setup(m => m.IsSignedIn(claimsPrincipal)).Returns(true);
var expected = new RedirectToPageResult("/Index");
// Act
var result = registerModel.OnGet();
//Assert
Assert.Equal(expected, result);
}
}
OnGet
method:
public IActionResult OnGet(string returnUrl = null)
{
// The test is supposed to result in the code inside of this IF executing
// but it continues on and fails at CreateGateway() because it is missing
// dependencies for that method.
if (_signInManager.IsSignedIn(User))
return new RedirectToPageResult("/Index");
ReturnUrl = returnUrl;
// Create gateway
Gateway = CreateGateway();
// Load clientToken
ClientToken = Gateway.ClientToken.Generate();
return Page();
}
Error:
Error Message:
System.NullReferenceException : Object reference not set to an instance of an object.
Stack Trace:
at Project.Areas.Identity.Pages.Account.RegisterModel.CreateGateway() in ... line 150
RegisterModel constructor:
public RegisterModel(
IConfiguration config,
UserManager<AppUser> userManager,
SignInManager<AppUser> signInManager,
UserValidator<AppUser> userValidator,
ILogger<RegisterModel> logger,
IEmailSender emailSender)
{
_config = config;
_userManager = userManager;
_signInManager = signInManager;
_userValidator = userValidator;
_logger = logger;
_emailSender = emailSender;
}
Not only does my test feel over-complicated but it is failing to trigger the IsSignedIn() mocked method and fails on a later line due to a lack of dependecies for the CreateGateway()
method.
Simply: How do I arrange a test for a PageModel handler requiring a UserManager<TUser>
and SignInManager<TUser>
for ASP .NET Core 3.0 or later ?
The issue in this case, is that the User
in the code under test
if (_signInManager.IsSignedIn(User))
does not match the principal configured in Setup
var claimsPrincipal = new TestPrincipal(new Claim("name", "John Doe"));
//...
mockSignInManager.Setup(m => m.IsSignedIn(claimsPrincipal)).Returns(true);
Which results in the mock not behaving as expected when the test is exercised and the condition evaluated.
I suggest loosening up the expectation using It.IsAny<>()
mockSignInManager
.Setup(_ => _.IsSignedIn(It.IsAny<ClaimsPrincipal>()))
.Returns(true);
Ideally I would have added an additional layer of abstraction to the PageModel to simplify its dependency on all those implementation concerns.
You should also refer to available documentation for tips on how to unit test razor pages
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.