为 Razor Pages 单元测试模拟用户 ClaimsPrincipal

3

我遇到了一个有关编写Razor页面结合MVVM单元测试的问题。我想要测试Razor中的OnPostAsync()方法,但是这个方法会调用另外两个需要ClaimsPrincipal用户的方法。然而,在我的测试中,我无法将User作为这些方法的参数。

目前我的测试方法如下:

[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", "0863629@hr.nl", 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();                        
}

我想要测试的方法:

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

 //(rest of the code...)

_validation.GetCurrentRole 方法:

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

我似乎无法让OnPostAsync/GetCurrentRole中的User不为null

我该如何将User分配给这些方法?


MakeBookingModel 上的 User 属性是只读的吗? - Nkosi
它继承自PageModel,并且似乎是公共的。 - RaspberryInIT
这应该会有所帮助 https://learn.microsoft.com/zh-cn/aspnet/core/test/razor-pages-tests?view=aspnetcore-2.1 - Nkosi
提供一个使用DefaultHttpContext的示例,这样您就不需要模拟它。 - Nkosi
无论你想做什么,这都不是一个单元测试。按照定义,单元测试测试的是一段代码,通常不超过一个方法。你对基础设施有太多的依赖,使得它成为了一个集成测试(在单元测试中,你不会使用内存数据库,而是会模拟一个仓储或类似的东西)。此外,我们不知道 MakeBookingModel 是什么。一个服务?模型类?从方法和反伪造令牌来看,它更像是一个控制器,这使得它更像是一个集成测试。对于它,请使用 TestServer 类。因此,你试图实现什么完全不清楚。 - Tseng
显示剩余3条评论
1个回答

10
通过PageModelPageContext在HTTP上下文中设置User
// 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

//...

参考ASP.NET Core中的Razor Pages单元测试

您正在混合使用异步和阻止调用,例如.Result,这会导致GetCurrentRole死锁。

重构为全程异步。

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

1
这似乎有效!非常感谢!我现在唯一的问题是测试本身没有进入第二个方法(CurrentRole = ... GetUserAsync()),但它似乎在第一部分后停止。但这将会有很大的帮助。 - RaspberryInIT
@RaspberryInIT,你遇到了死锁问题,请查看答案中的更新。 - Nkosi
1
谢谢您的帮助!我一直在为单元测试我的Razor页面而苦苦挣扎,因为它没有将上下文传递给模型,而我仍然需要访问User.Identity.Name,这真的很令人沮丧,而且我讨厌它需要如此多的代码行,但它解决了问题,所以非常感谢您! - dEv93

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接