Asp.Net Core 2.1 ApiController does not automatically validate model under unit test

有些话、适合烂在心里 提交于 2019-12-11 02:35:27

问题


I am using xUnit to unit test an ASP.NET Core 2.1 controller method that returns an ActionResult<T>. The controller class is decorated with the [ApiController] attribute so that the method, when running live, performs model validation automatically. However, the controller method does not automatically fire model validation in my unit test, and I can't figure out why.

Here is my Unit Test.

[Fact]
public async Task post_returns_400_when_model_is_invalid()
{
    // arrange
    var mockHttpClientFactory = new Mock<IHttpClientFactory>();
    var mockHttpMessageHandler = new Mock<FakeHttpMessageHandler> {CallBase = true};
    mockHttpMessageHandler.Setup(mock => mock.Send(It.IsAny<HttpRequestMessage>()))
        .Returns(new HttpResponseMessage(HttpStatusCode.Accepted)
        {
            Content = new StringContent("{\"response\": {\"numFound\": 0, \"start\": 0, \"docs\": []}}")
        });
    var httpClient =
        new HttpClient(mockHttpMessageHandler.Object)
        {
            BaseAddress = new Uri("http://localhost:8983/"),
            DefaultRequestHeaders = {{"Accept", "application/json"}}
        };
    mockHttpClientFactory.Setup(mock => mock.CreateClient("SolrApi")).Returns(httpClient);
    var slackOptions = Options.Create<SlackOptions>(new SlackOptions());
    var prdSolrService = new PrdSolrService(Options.Create<PrdOptions>(new PrdOptions()));
    var slackMessageService = new PrdSlackMessageService(new HtmlTransformService(), slackOptions);
    var controller = new SlackPrdController(slackOptions, mockHttpClientFactory.Object, prdSolrService, slackMessageService);
    var slackRequest = new SlackRequest();

    // act
    var sut = await controller.Post(slackRequest);

    // assert 
    // note: validation should fail and not return a SlackMessage, but validation is not firing
    // auto-validation is part of [ApiController] attribute on the Controller class
    Assert.IsType<BadRequestObjectResult>(sut.Result);
}

Here is the Controller method being tested.

[HttpPost]
public async Task<ActionResult<SlackMessage>> Post(SlackRequest request)
{
    if (request.Token != _slackOptions.Token)
    {
        ModelState.AddModelError("Token", "Invalid verification token.");
        return BadRequest(ModelState);
    }

    var solrUri = _solrService.SlackRequestToSolrUri(request);
    var client = _httpClientFactory.CreateClient("SolrApi");
    var raw = await client.GetStringAsync(solrUri);
    var response = _solrService.ParseSolrResponse(raw);
    var slackMessage = _slackMessageService.InitialMessage(response);

    return slackMessage;
}

Here is the SlackRequest model, where the Token property is required.

public class SlackRequest
{
    public SlackRequest() {}

    [JsonProperty("token")]
    [Required]
    public string Token { get; set; }

    [JsonProperty("team_id")]
    public string TeamId { get; set; }

    [JsonProperty("team_domain")]
    public string TeamDomain { get;set; }

    [JsonProperty("enterprise_id")]
    public string EnterpriseId { get; set; }

    [JsonProperty("enterprise_name")]
    public string EnterpriseName { get; set; }

    [JsonProperty("channel_id")]
    public string ChannelId { get; set; }

    [JsonProperty("channel_name")]
    public string ChannelName { get; set; }

    [JsonProperty("user_id")]
    public string UserId { get; set; }

    [JsonProperty("user_name")]
    public string UserName { get; set; }

    [JsonProperty("command")]
    public string Command { get;set; }

    [JsonProperty("text")]
    public string Text { get; set; }

    [Url]
    [JsonProperty("response_url")]
    public string ResponseUrl { get; set; }

    [JsonProperty("trigger_id")]
    public string TriggerId { get; set; }
}

回答1:


The controller class is decorated with the [ApiController] attribute so that the method, when run live, performs model validation automatically. However, the controller method does not automatically fire model validation in my unit test, and I can't figure out why.

The ApiControllerAttribute is metadata that is only relevant at run time by the infrastructure, so that means you will have to use TestServer in an integration test and actually request the action under test for it to be part of the test and recognized by the framework.

This is because as the request goes through the infrastructure, the attribute basically tags the controller/action to let an action filter (ModelStateInvalidFilter) inspect the model and update the model state of the request. If model is found to be invalid it will short circuit the request so that is does not even reach the action to be invoked.



来源:https://stackoverflow.com/questions/51543863/asp-net-core-2-1-apicontroller-does-not-automatically-validate-model-under-unit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!