如何为OAuth授权控制器单元测试配置GetOpenIddictServerRequest
如何在MS Tests中配置GetOpenIddictServerRequest进行控制器单元测试
我正在使用MS Tests编写基于OAuth授权的控制器单元测试,了解直接Mock HttpContext并非最佳实践,希望获得配置GetOpenIddictServerRequest的帮助。
相关代码片段
控制器端点代码
public async Task<IActionResult> Authorize() { var request = HttpContext.GetOpenIddictServerRequest() ?? throw new InvalidOperationException("The OpenID Connect request cannot be retrieved."); // 如果客户端指定了prompt=login,直接将用户代理重定向到登录页面 if (request.HasPrompt(Prompts.Login)) { // 为避免无限的登录->授权重定向,在重定向用户前从授权请求负载中移除prompt=login标志 var prompt = string.Join(" ", request.GetPrompts().Remove(Prompts.Login)); var parameters = Request.HasFormContentType ? Request.Form.Where(parameter => parameter.Key != Parameters.Prompt).ToList() : Request.Query.Where(parameter => parameter.Key != Parameters.Prompt).ToList(); parameters.Add(KeyValuePair.Create(Parameters.Prompt, new StringValues(prompt))); return Challenge( authenticationSchemes: IdentityConstants.ApplicationScheme, properties: new AuthenticationProperties { RedirectUri = Request.PathBase + Request.Path + QueryString.Create(parameters) }); } // 省略其他逻辑 }
GetOpenIddictServerRequest扩展方法
public static OpenIddictRequest? GetOpenIddictServerRequest(this HttpContext context) { if (context == null) { throw new ArgumentNullException("context"); } return context.Features.Get<OpenIddictServerAspNetCoreFeature>()?.Transaction?.Request; }
我尝试的HttpContext设置代码
_authorizationController.ControllerContext = new ControllerContext() { HttpContext = new DefaultHttpContext() { } };
解决方案
不需要Mock整个HttpContext,直接模拟OpenIddict依赖的Feature和Transaction即可,步骤如下:
- 创建并配置
OpenIddictRequest实例,设置测试需要的属性(比如Prompt) - 实例化
OpenIddictServerTransaction并关联上面的Request - 创建
OpenIddictServerAspNetCoreFeature并关联Transaction - 将Feature添加到HttpContext的Features集合中
- 把配置好的HttpContext赋值给控制器的ControllerContext
完整测试代码示例
// 1. 创建并配置OpenIddictRequest,模拟prompt=login的场景 var openIddictRequest = new OpenIddictRequest { Prompt = Prompts.Login }; // 2. 创建Transaction并关联Request var transaction = new OpenIddictServerTransaction { Request = openIddictRequest }; // 3. 创建Feature并关联Transaction var feature = new OpenIddictServerAspNetCoreFeature { Transaction = transaction }; // 4. 配置HttpContext并添加Feature var httpContext = new DefaultHttpContext(); httpContext.Features.Set<OpenIddictServerAspNetCoreFeature>(feature); // 5. 给控制器赋值配置好的HttpContext _authorizationController.ControllerContext = new ControllerContext { HttpContext = httpContext }; // 执行测试方法 var result = await _authorizationController.Authorize(); // 断言结果,验证是否返回ChallengeResult Assert.IsType<ChallengeResult>(result);
说明
这种方式贴合OpenIddict的内部调用逻辑,比Mock整个HttpContext更精准。如果需要测试其他场景(比如没有prompt=login的情况),只需要修改OpenIddictRequest的属性即可。
内容的提问来源于stack exchange,提问作者tthakar
相关产品推荐
相关产品推荐

