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/dotnet/architecture/microservices/multi-container-microservice-net-applications/test-aspnet-core-services-web-apps

https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0

https://www.roundthecode.com/dotnet/asp-net-core-web-api/asp-net-core-testserver-xunit-test-web-api-endpoints

有关管道的更多信息,来自 MSDN