ASP.NET Core 6 - 使用自定义 IModelBinder 解析 HttpRequest 查询的控制器的 xUnit 测试
我在测试解析查询字符串的自定义模型绑定程序时有点迷失。由于 API 已给出,现在必须迁移到 .NET CORE,因此我无法更改 url 查询参数的语法。所以我不能在控制器参数中使用 [FromQuery] 属性。
控制器很简单:
public class HostListController
: ControllerBase
{
[HttpGet]
public async Task<ActionResult<IList<SomeDto>>> Get(
CustomQueryExpr filter,
[FromQuery] bool pretty)
{
// do some fetch
}
}
并且自定义模型绑定器实现也很简单:
public class CustomQueryBinder
: IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var parser = new QueryParser();
//--- get queryString from request
var queryString = bindingContext.HttpContext.Request.QueryString;
//--- parse string
var queryExpr = parser.Parse(queryString.Value);
bindingContext.Result = ModelBindingResult.Success(queryExpr);
return Task.CompletedTask;
}
}
自定义QueryParser的具体实现并不重要,它的方法'Parse'返回一个'CustomQueryExpr ' 无论如何实例。
现在我正在努力组装测试。
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;
public class TestCustomQueryBinder
{
[Fact]
public async Task TestValidQuery_BindModel_ReturnCustomQueryExpr()
{
//--- assemble
var modelMetadata = new EmptyModelMetadataProvider();
var requestFake = new HttpRequestFeature();
requestFake.QueryString = "?filter_arg1=te*t&select=arg1,arg2";
var features = new FeatureCollection();
features.Set<IHttpRequestFeature>(requestFake);
var fakeHttpContext = new DefaultHttpContext(features);
var bindingContext = new DefaultModelBindingContext
{
ModelName = "CustomQueryExpr",
ModelMetadata = modelMetadata.GetMetadataForType(typeof(CustomQueryExpr)),
ActionContext = new ActionContext()
{
HttpContext = fakeHttpContext
}
};
var binder = new CustomQueryBinder();
//--- act
await binder.BindModelAsync(bindingContext);
//--- assert
Assert.NotNull(bindingContext.Result);
Assert.True(bindingContext.Result.IsModelSet);
Assert.True(bindingContext.Result.Model is CustomQueryExpr);
}
}
现在按预期工作。有时,简单地向他人解释问题有助于找出自己的错误……阿甘和树木。
但我确信这个解决方案可以改进,所以请添加您的评论、提示和改进以供学习。
I'm a bit lost in testing my custom modelbinder that parses a querystring. As the API is given and now must be migrated to .NET CORE, I am not able to change the syntax of the url query parameter. So I can not use the [FromQuery] attribute at the controllers parameter.
The controller is simple:
public class HostListController
: ControllerBase
{
[HttpGet]
public async Task<ActionResult<IList<SomeDto>>> Get(
CustomQueryExpr filter,
[FromQuery] bool pretty)
{
// do some fetch
}
}
And the custom model binder implementation is also straight forward:
public class CustomQueryBinder
: IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var parser = new QueryParser();
//--- get queryString from request
var queryString = bindingContext.HttpContext.Request.QueryString;
//--- parse string
var queryExpr = parser.Parse(queryString.Value);
bindingContext.Result = ModelBindingResult.Success(queryExpr);
return Task.CompletedTask;
}
}
The concrete implementation of the custom QueryParser is not important, it's method 'Parse' returns a 'CustomQueryExpr' instance in any case.
Now I'm struggling in assembling the test.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;
public class TestCustomQueryBinder
{
[Fact]
public async Task TestValidQuery_BindModel_ReturnCustomQueryExpr()
{
//--- assemble
var modelMetadata = new EmptyModelMetadataProvider();
var requestFake = new HttpRequestFeature();
requestFake.QueryString = "?filter_arg1=te*t&select=arg1,arg2";
var features = new FeatureCollection();
features.Set<IHttpRequestFeature>(requestFake);
var fakeHttpContext = new DefaultHttpContext(features);
var bindingContext = new DefaultModelBindingContext
{
ModelName = "CustomQueryExpr",
ModelMetadata = modelMetadata.GetMetadataForType(typeof(CustomQueryExpr)),
ActionContext = new ActionContext()
{
HttpContext = fakeHttpContext
}
};
var binder = new CustomQueryBinder();
//--- act
await binder.BindModelAsync(bindingContext);
//--- assert
Assert.NotNull(bindingContext.Result);
Assert.True(bindingContext.Result.IsModelSet);
Assert.True(bindingContext.Result.Model is CustomQueryExpr);
}
}
Works now as expected. Sometimes it helps to simply explain the problem to others to find the own mistake ... forrests and trees.
But I'm sure this solution can be improved, so please add your comments, hints and improvements to learn from.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论