how to manually run Controller FromBody validation

Viewed 26

How to run same model validation as it does on controllerValidation validation (using FromBody attribute) ?

I try to do it in my manualValidation endpoint as test example but I don't reach same results

Example: I send payload {"customerNumber": 33,"routingKey": null} to controllerValidation endpoint

and I get this result as expected

{
    "errors": {
        "routingKey": [
            "The RoutingKey field is required."
        ]
    }
  
}

If I run code shown manualValidation endpoint then it says that model is valid. I don't understand why cause RoutingKey property is null.

Model:

public class TestModel
{
    public long CustomerNumber { get; set; }

    public string RoutingKey { get; set; } = null!;//Should not be null
}

Controller:

[ApiController]
public class TestController : ControllerBase
{
    [HttpPost]
    [Route("controllerValidation")]
    public  TestModel Create([FromBody] TestModel model)
    {
        //false

        return model;
    }
}

When I run unit test then I get true as validation result

[TestMethod]
public void TestModel()
{
    var model = new TestModel();
    model.CustomerNumber = 33;
    var context = new ValidationContext(model);
    var results = new List<ValidationResult>();
    var isValid = Validator.TryValidateObject(model, context, results, true);//returns true , expect to have false cause RoutingKey is null
    Assert.IsFalse(isValid);
}

The only thing how to make it work properly in unit test it to add [Required] attribute to RoutingKey but that's not good solution as I have to do it for all models everywhere as well ... UPD:this is .NET6

1 Answers

The only thing how to make it work properly in unit test it to add [Required] attribute to RoutingKey

You can check the TryValidateObject source code, it validate the validation attribute on the property which is why you add the [Required] attribute the test works.

The correct way to judge the ModelState should be:

Test Method:

[TestClass()]
public class WeatherForecastControllerTests
{
    private readonly WeatherForecastController controller;
    private readonly ILogger<WeatherForecastController> logger;
    public WeatherForecastControllerTests()
    {
        
        controller = new WeatherForecastController(logger);
    }
    [TestMethod()]
    public void CreateTest()
    {
        var model = new TestModel();
        model.CustomerNumber = 33;
        
        controller.ModelState.AddModelError("RoutingKey", "Required");
        // Act
        controller.Create(model); 
        var isValid = controller.ModelState.IsValid;
      
        Assert.IsFalse(isValid);
    }
}

Method:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }
   
    [HttpPost]
    [Route("controllerValidation")]
    public TestModel Create([FromBody] TestModel model)
    {
        //false
        return model;
    }
}

Reference:

https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/testing?view=aspnetcore-6.0

Related