首页 > 解决方案 > Asp.Net Core 2.1 ApiController 不会在单元测试下自动验证模型

问题描述

我正在使用 xUnit 对返回ActionResult<T>. 控制器类使用该[ApiController]属性进行修饰,以便该方法在实时运行时自动执行模型验证。但是,控制器方法不会在我的单元测试中自动触发模型验证,我不知道为什么。

这是我的单元测试

[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);
}

这是正在测试的Controller方法。

[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;
}

这是SlackRequest 模型,其中需要 Token 属性。

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; }
}

标签: c#unit-testingasp.net-core-2.1

解决方案


控制器类使用 [ApiController] 属性进行修饰,以便该方法在实时运行时自动执行模型验证。但是,控制器方法不会在我的单元测试中自动触发模型验证,我不知道为什么。

ApiControllerAttribute数据仅在运行时与基础架构相关,因此这意味着您必须TestServer在集成测试中使用并实际请求被测操作以使其成为测试的一部分并被框架识别。

这是因为当请求通过基础设施时,该属性基本上标记控制器/动作以让动作过滤器 ( ModelStateInvalidFilter ) 检查模型并更新请求的模型状态。如果发现模型无效,它将使请求短路,从而甚至无法到达要调用的操作。


推荐阅读