I have class city:
public class City
{
public int Id { get; set; }
[Required(ErrorMessage = "This field is required (server validation)")]
public string Name { get; set; }
[Range(1, 100000000, ErrorMessage = "ZIP must be greater than 1 and less than 100000000 (server validation)")]
public int ZIP { get; set; }
[Range(1, 2000000000, ErrorMessage = "Population must be between 1 and 2B (server validation)")]
public int Citizens { get; set; }
public int CountryId { get; set; }
public Country Country { get; set; }
}
I have in controller post action for add city:
[HttpPost]
public IActionResult PostCity(City city)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_cityRepository.Add(city);
return CreatedAtAction("GetCity", new { id = city.Id }, city);
}
and I have test for invalid model:
[Fact]
public void PostCity_InvalidModel_ReturnsBadRequest()
{
// Arrange
City city = new City() { Id=15, Name = "", ZIP = 0, CountryId = 1, Citizens = 0 };
var mockRepository = new Mock<ICityRepositroy>();
var mapperConfiguration = new MapperConfiguration(cfg => cfg.AddProfile(new CityProfile()));
IMapper mapper = new Mapper(mapperConfiguration);
var controller = new CitysController(mockRepository.Object, mapper);
// Act
var actionResult = controller.PostCity(city) as BadRequestResult;
// Assert
Assert.NotNull(actionResult);
}
I debug test and I always get modelState.IsValid = true. When I try in postman to send invalid request, server validation works fine. Why my validation doesn’t work in my test? ASP .Net Core framework is 5.0.
>Solution :
Your test call the method controller.PostCity(city) directly, while in the web server, when calling the endpoint, a whole bunch of middle ware is triggered and executed first.
One of this being the modelbinder, which I believe also performs the model validation.
So this will not work, because calling the ModelState.IsValid without any further initialization, causes it to return true as by default:
var controller = new CitysController(mockRepository.Object, mapper);
// Act
var actionResult = controller.PostCity(city) as BadRequestResult;
In stead you either need to connect the proper validation mechanism of the model, or even better (IMO) use the test web server which can do this in an easy controllable way.
Here’s basically how to do it, but I recommend you to read some of the following articles as well (source: MSDN):
public class PrimeWebDefaultRequestShould
{
private readonly TestServer _server;
private readonly HttpClient _client;
public PrimeWebDefaultRequestShould()
{
// Arrange
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>());
_client = _server.CreateClient();
}
[Fact]
public async Task ReturnHelloWorld()
{
// Act
var response = await _client.GetAsync("/");
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
// Assert
Assert.Equal("Hello World!", responseString);
}
}
In the code above you’ll need to replace the likes like EnsureSuccessStatusCode with you actual BadRequest test case.
Some additional reads:
https://www.meziantou.net/testing-an-asp-net-core-application-using-testserver.htm
https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0
More info on the pipelines, by MSDN:

