Search code examples
unit-testingasp.net-coreasp.net-core-webapiasp.net-core-2.1

How do I unit test model validation in controllers decorated with [ApiController]?


As pointed out in this anwer to Asp.Net Core 2.1 ApiController does not automatically validate model under unit test, the automatic ModelState validation that ASP.NET Core 2.1's ApiControllerAttribute gives us only works when actualyy requestion the action at runtime, not by calling it with an invalid parameter in a unit test.

However, I still want to test if my action actually returns a BadRequestResult when supplying an incorrect model. Is there any way of doing this? I get that I can still manually check if ModelState.IsValid is false, and returning BadRequest() myself, but that kind of defeats the point of the automatic validation.

Am I stuck manually checking ModelState.IsValid after all, or is there a way to make use of the new ApiControllerAttribute model validation in a unit test?


Solution

  • If you want to validate that the api's are returning a badrequest when the data annotations are broken then you need to do an api integration test. One nice option is to run the integration tests via an in-memory client using the TestServer

    Here's an example:

    //arrange
    var b = new WebHostBuilder()
        .UseStartup<YourMainApplication.Startup>()
        .UseEnvironment("development");
    
    var server = new TestServer(b) { BaseAddress = new Uri(url) };
    var client = server.CreateClient();
    var json = JsonConvert.SerializeObject(yourInvalidModel);
    var content = new StringContent(json, Encoding.UTF8, "application/json");
    
    //act
    var result = await client.PostAsync("api/yourController", content);
    
    //assert
    Assert.AreEqual(400, (int)result.StatusCode);
    

    If you only need to make sure that the annotations is proper setup you can manually trigger the validation via the TryValidateObject method

    var obj = new YourClass();
    var context = new ValidationContext(obj);
    var results = new List<ValidationResult>();
    var valid = Validator.TryValidateObject(obj, context, results, true);