对于测试中的无效条目,ModelState.IsValid显示为真

人气:978 发布:2022-10-16 标签: validation c# asp.net-core-webapi

问题描述

我有班级城市:

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。当我尝试在邮递员中发送无效请求时,服务器验证工作正常。为什么我的验证在我的测试中不起作用?ASP.Net核心框架为5.0。

推荐答案

您的测试直接调用方法controller.PostCity(city),而在Web服务器中,调用终结点时,会先触发并执行一大堆中间件。

其中之一是模型绑定器,我认为它也执行模型验证。

因此这将不起作用,因为在没有任何进一步初始化的情况下调用ModelState.IsValid会导致它返回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:

746