Asp.Net Core 2.1 ApiController 不会在单元测试下自动验证模型
Asp.Net Core 2.1 ApiController does not automatically validate model under unit test
我正在使用 xUnit 对 ASP.NET Core 2.1 控制器方法进行单元测试,returns 和 ActionResult<T>
。控制器 class 装饰有 [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 模型,其中需要令牌 属性。
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; }
}
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.
ApiControllerAttribute
是基础架构仅在 运行 时间相关的元数据,因此这意味着您必须在集成测试中使用 TestServer
并实际请求操作under test 使其成为测试的一部分并被框架识别。
这是因为当请求通过基础架构时,属性基本上标记 controller/action 让操作过滤器 (ModelStateInvalidFilter) 检查模型并更新请求的模型状态。如果发现模型无效,它将使请求短路,以至于它甚至无法到达要调用的操作。
我正在使用 xUnit 对 ASP.NET Core 2.1 控制器方法进行单元测试,returns 和 ActionResult<T>
。控制器 class 装饰有 [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 模型,其中需要令牌 属性。
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; }
}
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.
ApiControllerAttribute
是基础架构仅在 运行 时间相关的元数据,因此这意味着您必须在集成测试中使用 TestServer
并实际请求操作under test 使其成为测试的一部分并被框架识别。
这是因为当请求通过基础架构时,属性基本上标记 controller/action 让操作过滤器 (ModelStateInvalidFilter) 检查模型并更新请求的模型状态。如果发现模型无效,它将使请求短路,以至于它甚至无法到达要调用的操作。