RaspberryInIT
RaspberryInIT

Reputation: 43

Mocking User ClaimsPrincipal for Razor Pages Unit Test

I have an issue regarding writing a unit test for a Razor Page combined with MVVM. I want to test an OnPostAsync() method from Razor, however this method will call two more methods which require a ClaimsPrincipal User. I can't give the User as a parameter for these methods from within my test however.

My current test method:

[Test]
public void MakeBookingTest()
{            
    //Arrange
    var optionsbuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
    optionsbuilder.UseInMemoryDatabase(databaseName: "TeacherDB");
    var _dbContext = new ApplicationDbContext(optionsbuilder.Options);

    JsonResult json = new JsonResult(true);
    _dbContext.ImportOption.Add(new ImportOption { Id = 1, isUnique = 1, Option = "Teacher" });
    _dbContext.SaveChanges();

    var mockedUserManager = GetMockUserManager();           

    var mockedCalendar = new Mock<ICalendarService>();

    Booking booking = new Booking {
        EventId = "2",
        ClassroomId = 3,
        BeginTime = DateTime.Now,
        EndTime = DateTime.Now,
        Description = "fjdkafjal",
        Summary = "Test01" };

    mockedCalendar.Setup(x => x.CreateEvent(booking, "2", "[email protected]", false)).Returns("111");

    var mockedRoleManager = GetMockRoleManager();

    var model = new MakeBookingModel(_dbContext, mockedUserManager.Object, mockedCalendar.Object, mockedRoleManager.Object);
    //var controllerContext = new Mock<ControllerContext>();

    var result = model.OnPostAsync();                        
}

The method which I want to test:

[ValidateAntiForgeryToken]
public async Task<IActionResult> OnPostAsync()
{
    CurrentRole = await _validation.GetCurrentRole(User);
    CurrentUser = await _userManager.GetUserAsync(User);

 //(rest of the code...)

_validation.GetCurrentRole method:

public async Task<string> GetCurrentRole(ClaimsPrincipal User)
{
    ApplicationUser currentUser = await _userManager.GetUserAsync(User);            
    Task<IList<string>> rolesUser = _userManager.GetRolesAsync(currentUser);
    return rolesUser.Result.First();
}

I can't seem to make User in the OnPostAsync/GetCurrentRole to not be null.

How would I assign User to those methods?

Upvotes: 3

Views: 1806

Answers (1)

Nkosi
Nkosi

Reputation: 247471

Set the User via the HTTP context which is part of the PageModel's PageContext

// Arrange

//...code removed for brevity

//Create test user
var displayName = "User name";
var identity = new GenericIdentity(displayName);
var principle = new ClaimsPrincipal(identity);
// use default context with user
var httpContext = new DefaultHttpContext() {
    User = principle
}
//need these as well for the page context
var modelState = new ModelStateDictionary();
var actionContext = new ActionContext(httpContext, new RouteData(), new PageActionDescriptor(), modelState);
var modelMetadataProvider = new EmptyModelMetadataProvider();
var viewData = new ViewDataDictionary(modelMetadataProvider, modelState);
// need page context for the page model
var pageContext = new PageContext(actionContext) {
    ViewData = viewData
};
//create model with necessary dependencies
var model = new MakeBookingModel(_dbContext, mockedUserManager.Object, mockedCalendar.Object, mockedRoleManager.Object) {
    PageContext = pageContext
};

//Act

//...

Reference Razor Pages unit tests in ASP.NET Core

You are mixing async and blocking calls like .Result which is causing a deadlock in GetCurrentRole.

Refactor to be async all the way through

public async Task<string> GetCurrentRole(ClaimsPrincipal User) {
    ApplicationUser currentUser = await _userManager.GetUserAsync(User);            
    var rolesUser = await _userManager.GetRolesAsync(currentUser);
    return rolesUser.FirstOrDefault();
}

Upvotes: 10

Related Questions