ModelState.IsValid 对测试中的无效条目显示为真
ModelState.IsValid show true for invalid entry on Test
我有 class 个城市:
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; }
}
我在控制器 post 中有添加城市的操作:
[HttpPost]
public IActionResult PostCity(City city)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_cityRepository.Add(city);
return CreatedAtAction("GetCity", new { id = city.Id }, city);
}
并且我测试了无效模型:
[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);
}
我调试测试,我总是得到 modelState.IsValid = true。当我尝试在 postman 中发送无效请求时,服务器验证工作正常。为什么我的验证在我的测试中不起作用? ASP .Net Core 框架是 5.0.
这是因为当您启动 WebApi 并向其发送真实请求时,它会在调用控制器操作之前在后台调用多种方法来验证您的请求。在这些方法中,它将 ModelState.IsValid 属性 设置为 false。另一方面,当您直接从测试中调用控制器操作时,没有任何内容会验证您的请求,因此您的 ModelState.IsValid 默认设置为 true。
你的测试直接调用方法controller.PostCity(city)
,而在网络服务器中,当调用端点时,首先触发并执行一大堆中间件。
其中之一是模型绑定器,我相信它也执行模型验证。
所以这是行不通的,因为在没有任何进一步初始化的情况下调用 ModelState.IsValid
,默认情况下会导致 return true
:
var controller = new CitysController(mockRepository.Object, mapper);
// Act
var actionResult = controller.PostCity(city) as BadRequestResult;
相反,您要么需要连接模型的正确验证机制,要么更好 (IMO) 使用测试 Web 服务器,它可以以一种简单可控的方式执行此操作。
基本操作方法如下,但我建议您也阅读以下一些文章 (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);
}
}
在上面的代码中,您需要用实际的 BadRequest
测试用例替换 EnsureSuccessStatusCode
之类的内容。
一些额外的阅读:
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
有关管道的更多信息,来自 MSDN:
我有 class 个城市:
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; }
}
我在控制器 post 中有添加城市的操作:
[HttpPost]
public IActionResult PostCity(City city)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_cityRepository.Add(city);
return CreatedAtAction("GetCity", new { id = city.Id }, city);
}
并且我测试了无效模型:
[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);
}
我调试测试,我总是得到 modelState.IsValid = true。当我尝试在 postman 中发送无效请求时,服务器验证工作正常。为什么我的验证在我的测试中不起作用? ASP .Net Core 框架是 5.0.
这是因为当您启动 WebApi 并向其发送真实请求时,它会在调用控制器操作之前在后台调用多种方法来验证您的请求。在这些方法中,它将 ModelState.IsValid 属性 设置为 false。另一方面,当您直接从测试中调用控制器操作时,没有任何内容会验证您的请求,因此您的 ModelState.IsValid 默认设置为 true。
你的测试直接调用方法controller.PostCity(city)
,而在网络服务器中,当调用端点时,首先触发并执行一大堆中间件。
其中之一是模型绑定器,我相信它也执行模型验证。
所以这是行不通的,因为在没有任何进一步初始化的情况下调用 ModelState.IsValid
,默认情况下会导致 return true
:
var controller = new CitysController(mockRepository.Object, mapper);
// Act
var actionResult = controller.PostCity(city) as BadRequestResult;
相反,您要么需要连接模型的正确验证机制,要么更好 (IMO) 使用测试 Web 服务器,它可以以一种简单可控的方式执行此操作。
基本操作方法如下,但我建议您也阅读以下一些文章 (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);
}
}
在上面的代码中,您需要用实际的 BadRequest
测试用例替换 EnsureSuccessStatusCode
之类的内容。
一些额外的阅读:
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
有关管道的更多信息,来自 MSDN: