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.
CodePudding user response:
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 (
CodePudding user response:
It's because when you start the WebApi, and send a real request to it, behind the scenes it calls several methods in which it's validating your request, before it calls your controller action. In those methods it's setting the ModelState.IsValid property to false. On the other hand when you call your controller action directly from tests, nothing validates your request, hence your ModelState.IsValid is set to true by default.