C#中如何为带FromRoute特性的控制器属性编写单元测试?
问题根源
ASP.NET Core中标记了[FromRoute]的控制器属性,是框架在请求处理流程中,自动从路由数据中解析并赋值的。你在单元测试中手动实例化控制器时,默认不会执行这套绑定逻辑,且你初始化ControllerContext时传入了空的RouteData,所以RoomId属性会是null。
解决方案
方案1:手动填充RouteData+触发模型绑定
如果你希望模拟真实请求的绑定流程,可以先给RouteData填充对应参数,再调用绑定方法:
var routeData = new RouteData(); // 路由参数名要和路由模板里的参数完全一致 routeData.Values.Add("RoomId", "a8e3e87d-21e9-4a23-92cc-a50a662c1556"); routeData.Values.Add("version", "1.0"); var controller = new ParticipantController() { ControllerContext = new ControllerContext(new ActionContext( HttpUtilities.TestHttpContext("/v1.0/rooms/a8e3e87d-21e9-4a23-92cc-a50a662c1556/participants"), routeData, new ControllerActionDescriptor())) }; // 手动触发属性绑定 await controller.TryUpdateModelAsync(controller);
方案2:直接给私有属性赋值(单元测试推荐)
单元测试场景下不需要完全模拟框架流程,直接给目标属性赋值即可,代码更简单:
方式A:用反射赋值(不需要修改原有控制器代码)
var controller = new ParticipantController(); // 获取私有属性的set方法 var roomIdProperty = typeof(ParticipantController).GetProperty("RoomId", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); roomIdProperty.SetValue(controller, "a8e3e87d-21e9-4a23-92cc-a50a662c1556");
方式B:修改属性访问权限(适合经常需要测试的场景)
先在控制器项目的AssemblyInfo.cs中添加特性,把内部成员暴露给测试项目:
[assembly: InternalsVisibleTo("你的测试项目程序集名称")]
然后修改控制器的RoomId属性定义:
[FromRoute] private string RoomId { get; internal set; }
测试时就可以直接赋值:
var controller = new ParticipantController(); controller.RoomId = "a8e3e87d-21e9-4a23-92cc-a50a662c1556";
内容的提问来源于stack exchange,提问作者Woody1193
相关产品推荐
相关产品推荐

