You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core 2.1自定义ActionFilterAttribute单元测试descriptor为null修复求助

Fixing Null ControllerActionDescriptor in Action Filter Unit Test

Ah, I spot the issue immediately! Your test is using a generic ActionDescriptor instance, but your filter expects a ControllerActionDescriptor—that's why the cast returns null, and none of your validation logic actually runs. Let's fix this step by step.

The Root Cause

Your filter depends on ControllerActionDescriptor to access the action method's parameters via MethodInfo.GetParameters(). But in your original test, you're passing a base ActionDescriptor (via Mock.Of<ActionDescriptor>()), which can't be cast to the more specific ControllerActionDescriptor type.

Fixed Test Code

Here's the adjusted test that properly sets up a valid ControllerActionDescriptor and ensures your filter can execute its full logic:

[TestMethod]
public void ValidateModelAttributes_SetsResultToBadRequest_IfModelIsInvalid()
{
    // Arrange
    var validationFilter = new ValidateModelStateAttribute();
    var modelState = new ModelStateDictionary();
    modelState.AddModelError("name", "invalid");

    // Create a dummy controller method to get valid MethodInfo for the descriptor
    // This mimics a real controller action with a parameter named "name"
    var dummyActionMethod = typeof(DummyTestController).GetMethod(nameof(DummyTestController.ValidateNameAction));
    
    // Use ControllerActionDescriptor instead of the base ActionDescriptor
    var actionDescriptor = new ControllerActionDescriptor
    {
        MethodInfo = dummyActionMethod,
        ControllerName = nameof(DummyTestController),
        ActionName = nameof(DummyTestController.ValidateNameAction)
    };

    var actionContext = new ActionContext(
        Mock.Of<HttpContext>(), 
        Mock.Of<RouteData>(), 
        actionDescriptor, // Pass the valid ControllerActionDescriptor here
        modelState
    );

    // Match the ActionArguments key to the parameter name from our dummy method
    var actionExecutingContext = new ActionExecutingContext(
        actionContext, 
        new List<IFilterMetadata>(), 
        new Dictionary<string, object>() { { "name", "test-value" } }, // Key matches parameter name
        Mock.Of<Controller>()
    );

    // Act
    validationFilter.OnActionExecuting(actionExecutingContext);

    // Assert
    Assert.IsNotNull(actionExecutingContext.Result);
    // Optional: Add a more specific assertion to confirm it's a BadRequest
    Assert.IsInstanceOfType(actionExecutingContext.Result, typeof(BadRequestObjectResult));
}

// Dummy controller class to provide a valid MethodInfo for the test
private class DummyTestController : Controller
{
    public IActionResult ValidateNameAction(string name)
    {
        return Ok();
    }
}

Key Changes Explained

  1. Dummy Controller & Action: We added a lightweight DummyTestController with an action method that has a name parameter. This gives us a valid MethodInfo to assign to the ControllerActionDescriptor, so your filter can call GetParameters() without null reference errors.
  2. Concrete ControllerActionDescriptor: Instead of using a mocked base ActionDescriptor, we create a real ControllerActionDescriptor instance and populate its required properties (MethodInfo, ControllerName, ActionName).
  3. Matching Action Arguments: The ActionArguments dictionary now uses a key (name) that exactly matches the parameter name from our dummy action. This ensures your filter can retrieve the argument value correctly during validation.

With these changes, the cast context.ActionDescriptor as ControllerActionDescriptor will return a valid instance, your filter will run through the parameter validation logic, and your assertion will pass when the model state is invalid.

内容的提问来源于stack exchange,提问作者Kevin YANG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:10:15